Лимиты: все четыре правила ADR-021 — регистрация 5/час на IP, вход 10/10 мин на IP и ник, сообщения 30/мин, прочие изменяющие 60/мин; 429 с Retry-After; X-Real-IP читается только с loopback, иначе адрес соединения — иначе заголовок отменял бы лимит на IP; карты вёдер ограничены поколениями. Аудит нашёл то, что пропустили пять раундов ревью: ADR-056: nginx вёл access_log с IP и полными путями вопреки обещанию deploy.md. Ники и социальный граф ложились в /var/log/nginx рядом с чистым журналом bare. ADR-058: «выйти на других устройствах» не обрывал уже открытый SSE — отозванная сессия продолжала получать сообщения. ADR-059: промежуточный ключ комнаты был невосстановим. Участник, пропустивший офлайн два rekey подряд, навсегда не расшифровал бы сообщения среднего ключа — вопреки обещанию storage.md о повторной попытке после получения keyId. ADR-063: ACK уходил по одному на конверт, а не пачкой. Получатель в оживлённой комнате выедал общее ведро подтверждениями и упирался в 429 на всех изменяющих запросах, включая выход из комнаты: 116 отказов за прогон стало нулём. ADR-055, 057, 060, 061, 062: ключи вёдер и границы, +dirty у bare version, 403 unknown_device не хоронит сообщение, усечение имени в подсказке ввода, kdf как оракул после повышения цели KDF. Модель угроз пополнена тем, что действительно видит оператор: push-подписки лежат в базе открытым текстом, и вместе с VAPID-ключом с той же машины это произвольное уведомление на экране блокировки. README приведён к v1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015DbCjVfTFq4ZFG8juD45YJ
46 lines
9.2 KiB
Markdown
46 lines
9.2 KiB
Markdown
# Модель угроз
|
||
|
||
Честная. Здесь написано не только что Bare защищает, но и чего он защитить не может.
|
||
|
||
## Что защищаем
|
||
|
||
Содержимое сообщений. Оно шифруется на устройстве отправителя и расшифровывается на устройствах получателей. Сервер, канал и оператор видят только шифротекст.
|
||
|
||
## От кого защищаем
|
||
|
||
**Пассивный оператор сервера.** Админ с полным доступом к базе, диску и логам запросов видит: ники, argon2-хеши от `authKey`, зашифрованные ключевые блобы, имена комнат и составы, завёрнутые ключи комнат, транзитную очередь шифротекстов, push-подписки устройств — адрес push-сервиса и ключи подписки `p256dh` и `auth`. Пароль на сервер не приходит (ADR-015) — в логах запросов материала ключа нет. Плейнтекста у него нет. База вместе с VAPID-ключом, который лежит на той же машине в `/etc/bare/env`, позволяет показать устройству произвольное уведомление от имени bare — вплоть до фишингового текста на экране блокировки; содержимого сообщений это не раскрывает.
|
||
|
||
**Сетевой наблюдатель.** HTTPS обязателен. Наблюдатель видит факт и объём трафика к серверу, не содержимое.
|
||
|
||
**Кража базы или бэкапа.** В базе нет ничего сверх того, что видит оператор: те же шифротексты и метаданные.
|
||
|
||
**Push-инфраструктура.** Пуш не несёт содержимого: сервер не знает плейнтекста, поэтому его нет и в пуше.
|
||
|
||
## От кого не защищаем
|
||
|
||
**Активно-злонамеренный оператор.** Оператор, способный подменить клиентский код, может украсть ключи и плейнтекст. Это фундаментальный предел web-E2EE: клиент каждый раз загружается с сервера. Смягчение — открытый код, клиент из нескольких читаемых файлов без сборки, статика внутри бинаря, хеш которого сверяется со сборкой из тега: подмену можно заметить. Гарантии нет.
|
||
|
||
**Подмена публичного ключа.** Ключи раздаёт сервер. Защита — TOFU (ADR-016): подмена возможна только при первом контакте, дальше клиент видит смену ключа и блокирует отправку до подтверждения отпечатка. Защита работает ровно настолько, насколько люди сверяют отпечатки; если не сверяют — первый контакт остаётся на доверии к серверу.
|
||
|
||
**Подделка отправителя в комнате.** Подписей нет; `from` ставит сервер. Участник комнаты может создать валидный шифротекст, но приписать его другому — только в сговоре с сервером. В 1:1 подделка невозможна без общего секрета.
|
||
|
||
**Метаданные.** Кто, с кем, когда и сообщениями какого размера обменивается, имена комнат и их составы, список устройств, когда они появлялись и куда им слать пуши, — серверу видно. Скрытие метаданных — не задача Bare.
|
||
|
||
**Компрометация устройства.** История лежит на устройстве в открытом виде (IndexedDB), там же — приватный ключ и секрет аккаунта как non-extractable `CryptoKey`. Доступ к устройству — доступ к истории и возможность писать от имени владельца. Защита устройства — зона ответственности пользователя и ОС. XSS в клиенте — отдельный риск того же класса; смягчение — CSP без исключений и запрет `innerHTML`.
|
||
|
||
**Слабый пароль.** Пароль — материал ключа. Ключевой блоб хранится на сервере, и его стойкость к оффлайн-перебору равна стойкости пароля. Гарантия «оператор не читает сообщения» действует в пределах стойкости пароля пользователя: слабый пароль — слабое E2EE. Это осознанная цена парольного мультидевайса. Контрмеры (ADR-013): PBKDF2-HMAC-SHA256 с не менее чем 600 000 итераций, пароль от 12 символов, рекомендация парольной фразы в UI.
|
||
|
||
**Собеседник.** E2EE не защищает от участника чата: получатель может сохранить, переслать, сфотографировать. «Удалить у всех» после доставки не существует.
|
||
|
||
**Сам владелец истории.** Привязка экспорта к аккаунту (ADR-014) защищает файл, а не содержимое от владельца. Пользователь, желающий отдать переписку третьему лицу, сделает это скриншотами или модифицированным клиентом — «аналоговая дыра» криптографией не закрывается. К тому же у собеседников есть собственные копии тех же сообщений. Смысл привязки: перемещённый — случайно или злонамеренно — файл `.bare` бесполезен для посторонних.
|
||
|
||
## Осознанные пределы v1
|
||
|
||
**Forward secrecy отсутствует.** Компрометация приватного ключа пользователя раскрывает ранее записанные атакующим шифротексты его чатов 1:1 и завёрнутые ключи комнат. Осознанный non-goal v1.
|
||
|
||
**Вышедший участник до rekey.** После выхода участника сервер перестаёт доставлять ему сообщения, а новый ключ комнаты создаёт владелец при следующем появлении. В промежутке вышедший участник знает действующий ключ; прочитать новые сообщения он может только в сговоре с сервером.
|
||
|
||
**Push-транспорт идёт через инфраструктуру вендоров браузеров** (FCM, APNs, Mozilla). Это свойство стандарта Web Push, а не наша зависимость. Вендоры видят факт и время доставки пуша.
|
||
|
||
**Сервер сам ходит по адресу, который выбрал браузер получателя.** Адрес push-сервиса приходит в подписке от клиента, и на каждое сообщение сервер открывает к нему исходящее соединение. Белого списка вендоров нет и не будет: адреса вендоров меняются, а подписку выдаёт браузер. Ограничения — ADR-047: только `https`, только публичные адреса (проверяется уже разрешённый адрес соединения), без следования за редиректами, адрес подписки в журнал не пишется. Остаток риска принят: аутентифицированный пользователь может заставить сервер обратиться к произвольному публичному адресу — до четырёх POST на аккаунт-получателя (доля аккаунта в отправке, ADR-048), то есть до 4×N на сообщение в комнату из N участников, в пределах общих лимитов и восьми отправщиков.
|