118 lines
12 KiB
Markdown
118 lines
12 KiB
Markdown
# Безопасность и модель угроз MVP
|
||
|
||
- Пароль XMPP сохраняется в Keychain и не попадает в `UserDefaults` или
|
||
локальное хранилище истории.
|
||
- Проверка сертификата не отключается. Ручной host меняет маршрут подключения,
|
||
но XMPP domain/JID остаётся исходной идентичностью.
|
||
- TLS trust оценивается системным Apple Security framework как сертификат
|
||
сервера (`SecPolicyCreateSSL(true, ...)`) для домена из JID; hostname и цепочка
|
||
доверия обязательны даже при ручном адресе подключения.
|
||
- Приложение можно заблокировать паролем (хранится в Keychain, выключено по
|
||
умолчанию): блокировка срабатывает при запуске и при уходе в фон, а
|
||
разблокировка возможна по Face ID/Touch ID.
|
||
- Пароль для SCRAM нормализуется по RFC 4013 (SASLprep), чтобы совпадать с
|
||
серверной нормализацией; для PLAIN пароль отправляется как введён.
|
||
- SCRAM доступен в вариантах SHA-512, SHA-256 и SHA-1 (SHA-512 —
|
||
реализация Luma), а также в PLUS-вариантах с канальной привязкой
|
||
(SCRAM-SHA-512-PLUS > SHA-256-PLUS > SHA-1-PLUS): gs2-заголовок
|
||
«p=tls-exporter,» (RFC 9266) или «p=tls-server-end-point,» доказывает,
|
||
что SASL-обмен идёт по тому же TLS-каналу, который видит клиент, и
|
||
ломает MITM-ретрансляцию. PLUS выбирается только когда сервер
|
||
рекламирует соответствующий channel-binding тип, иначе — обычный SCRAM;
|
||
механизм выбирается по рекламе сервера.
|
||
- OMEMO работает в legacy-неймспейсе `eu.siacs.conversations.axolotl` (так
|
||
умеет закреплённая версия MartinOMEMO) и в OMEMO 2 (`urn:xmpp:omemo:2`,
|
||
payload AES-256-CBC + HMAC-SHA-256 в конверте SCE `urn:xmpp:sce:0`). Luma
|
||
публикует omemo:2 bundle и список устройств, делит Double Ratchet-сессии с
|
||
legacy-модулем и помечает протокол каждого ключа на экране шифрования.
|
||
- Канал шифруется STARTTLS/direct TLS собственным TLS-процессором Luma на
|
||
OpenSSL 3 (SecureTransport ограничивает потоковый TLS версией 1.2 и не
|
||
имеет keying exporter): минимум TLS 1.2, максимум TLS 1.3, ALPN
|
||
«xmpp-client», SNI по домену XMPP. Сертификат проверяется через
|
||
SecTrust с серверной политикой домена из JID (та же логика
|
||
CertificateTrustEvaluator). Фактическая версия TLS, шифр и выбранный
|
||
SASL-механизм (самый стойкий из рекламируемых сервером, с канальной
|
||
привязкой при её доступности) показываются на экране информации о
|
||
сервере.
|
||
- Когда OMEMO включено глобально или для конкретного чата, исходящие сообщения
|
||
не откатываются на plaintext при ошибке: ошибка показывается пользователю.
|
||
- Пользователь может осознанно отключить OMEMO глобально или для отдельного
|
||
чата. В этом режиме сервер, MAM-хранилище и участники TLS-терминации видят текст.
|
||
- OMEMO доступно и для XEP-0045, но только в неанонимной комнате: клиенту нужны
|
||
реальные bare JID участников, чтобы зашифровать ключ для каждого устройства и
|
||
расшифровать входящее сообщение от правильной Signal identity. Luma проверяет
|
||
режим комнаты, собирает online occupants и доступные списки member/admin/owner,
|
||
а при скрытом JID или отсутствии устройств отменяет отправку без plaintext
|
||
fallback. Новые комнаты Luma создаются members-only и persistent с
|
||
`muc#roomconfig_whois=anyone`.
|
||
- Первый увиденный ключ получает доверие TOFU. Изменившийся ключ становится
|
||
undecided и требует ручной проверки отпечатка.
|
||
- При включённом OMEMO вложения шифруются до загрузки, а URL с ключом находится
|
||
внутри OMEMO payload. При выключенном OMEMO файл хранится на HTTP Upload
|
||
сервисе в исходном виде; ссылка и метаданные также не имеют E2EE.
|
||
- Даже для зашифрованного blob HTTP Upload сервис видит размер и транспортное
|
||
имя файла; у voice/video-note это имя содержит тип и округлённую длительность.
|
||
- Клиент принимает только HTTPS `put`/`get` URL от XEP-0363 компонента и не
|
||
понижает транспорт загрузки до обычного HTTP.
|
||
- В OMEMO-исправлении новое тело зашифровано, но стандартный XEP-0308
|
||
`<replace>` остаётся метаданными stanza: сервер видит id исправляемого
|
||
сообщения, но не новый текст.
|
||
- Ответ содержит id исходного сообщения и JID его автора. В зависимости от
|
||
поведения OMEMO-библиотеки и клиента эти XEP-0461 метаданные могут быть видны
|
||
серверу, даже когда текст ответа зашифрован.
|
||
- XEP-0424 не гарантирует стирание: retract может быть проигнорирован сервером
|
||
или клиентом, а получатель мог сохранить исходный текст. Fallback retraction
|
||
намеренно общий и никогда не повторяет удаляемое содержимое.
|
||
- Для inline-preview расшифрованные фото, видео, музыка и голосовые временно
|
||
записываются в sandbox `tmp`; Luma очищает известные preview-файлы при смене
|
||
аккаунта, а ОС может удалить их раньше как временные данные.
|
||
- Выбранные для пакетной отправки файлы временно копируются в `tmp` для экрана
|
||
предпросмотра и удаляются при отмене либо после завершения отправки.
|
||
- Core Location вызывается только из экрана явной отправки точки. Выбранные
|
||
координаты становятся содержимым сообщения и защищены OMEMO лишь тогда, когда
|
||
шифрование включено для этого чата; при plaintext сервер и MAM видят точку.
|
||
- Аудио/видео звонка шифруются WebRTC DTLS-SRTP между конечными клиентами.
|
||
Это не OMEMO: XMPP-сервер видит Jingle-сигналинг и адрес собеседника, а
|
||
STUN/TURN-сервис видит сетевые адреса и объём трафика. TURN ретранслирует уже
|
||
зашифрованный медиапоток. Если Prosody не публикует собственный сервис через
|
||
XEP-0215, резервный публичный STUN получает запрос на определение адреса.
|
||
- На iOS файл OMEMO-состояния и база локальной истории (SwiftData
|
||
`.store`) получают data-protection `completeUntilFirstUserAuthentication`.
|
||
|
||
- Архивные эхо собственных служебных станз (receipts, chat markers,
|
||
повторно доставленные копии) и собственные сообщения, которые невозможно
|
||
расшифровать обратно (нет encrypt-to-self ключа или self-сессия устарела),
|
||
не превращаются в пузыри «Не удалось расшифровать сообщение»: они
|
||
отбрасываются, как это делают другие клиенты, чтобы не засорять историю
|
||
фантомами, которых нет в виде сообщений на сервере.
|
||
- Сохранение медиа выполняется только по явному действию пользователя:
|
||
фото/видео/видеосообщения — в медиатеку, файлы и голосовые — в «Файлы»
|
||
(Загрузки). Расшифрованное содержимое при этом покидает sandbox приложения.
|
||
|
||
## Известные ограничения
|
||
|
||
- На macOS история (SwiftData SQLite в Application Support) и OMEMO state
|
||
лежат в sandbox без дополнительного SQLCipher-слоя; защиту обеспечивает
|
||
учётная запись и FileVault пользователя. Для повышенной модели угроз нужна
|
||
зашифрованная база.
|
||
- Локальная история содержит уже расшифрованные тексты, как и у большинства
|
||
клиентов. Полное удаление требует выхода с опцией удаления истории.
|
||
- «Удалить у меня» удаляет запись только из локального SwiftData-хранилища
|
||
этого устройства и запоминает id против повторной MAM-загрузки; оно не
|
||
удаляет серверный архив, другие собственные устройства или копию собеседника.
|
||
- Глобальная политика шифрования хранится в `UserDefaults` отдельно для каждого
|
||
JID, а переопределение чата — в локальном SwiftData-хранилище. Эти значения
|
||
не являются секретами, но прямо влияют на конфиденциальность следующей
|
||
отправки.
|
||
- Аватары XEP-0084/vCard не шифруются OMEMO. Их видимость определяется
|
||
настройками PEP и roster на сервере; не используйте аватар как секретное фото.
|
||
- Используемая реализация MartinOMEMO поддерживает распространённый legacy
|
||
namespace. Она не должна называться полной реализацией новой редакции
|
||
XEP-0384 без отдельного interoperability test suite.
|
||
- В открытой или плохо настроенной сторонней MUC списки офлайн-участников могут
|
||
быть недоступны. Для предсказуемого группового OMEMO используйте members-only
|
||
комнату, разрешающую участникам получать affiliation lists; иначе отключите
|
||
OMEMO именно для этой комнаты осознанно.
|
||
- Jailbreak/root, скомпрометированный endpoint и запись экрана находятся вне
|
||
модели угроз MVP.
|