Описание оригинального плагина
| Краткое описание | Discourse Encrypt обеспечивает частную зашифрованную передачу сообщений между конечными пользователями. Вся конфиденциальная информация надежно хранится на сервере и шифруется/расшифровывается только на стороне клиента. | |
| Ссылка на репозиторий | https://github.com/discourse/discourse-encrypt | |
| Руководство по установке | Как установить плагины в Discourse |
Три простых шага для использования этого плагина
- Включите шифрование и активируйте текущее устройство.
- Отправьте зашифрованное сообщение. Получатель также должен включить шифрование.
При желании вы можете определить время, через которое всё сообщение или конкретный пост будут безвозвратно удалены.
- Читайте секретные сообщения. Для их чтения необходимо сначала активировать шифрование.
Примечание: В этом примере пользователю снова предложили ввести бумажный ключ, потому что шифрование было деактивировано (например, при выходе из системы или явной деактивации в настройках).
Техническая информация
Этот плагин дает пользователям возможность безопасно общаться через Discourse, используя схему сквозного шифрования. Большая часть логики плагина реализована на стороне клиента, а сервер обрабатывает только открытые или зашифрованные данные. Он не шифрует метаданные сообщений, такие как имена участников беседы, время публикации, лайки, мелкие действия и т.д.; вложения шифруются, но факт их наличия не скрывается, так как системе необходимо связывать вложения с постами, чтобы предотвратить их удаление.
Весь код является открытым исходным кодом, и энтузиасты безопасности приглашаются к его проверке. Для получения дополнительной информации не стесняйтесь обращаться ко мне или к команде. ![]()
читать далее...
Краткое описание
Цель этого плагина — обеспечить целостность и конфиденциальность зашифрованного содержимого, а также защитить его от утечек информации и несанкционированного доступа. В следующих разделах описаны обычный режим работы, используемые алгоритмы и модели угроз.
Для использования этой системы пользователи один раз проходят регистрацию, генерируя «идентификатор пользователя», состоящий из двух 4096-битных RSA-ключей: один для шифрования, другой для подписи. Пользователи могут экспортировать свой «идентификатор» для безопасного хранения или сохранить его на сервере, зашифровав после создания бумажного ключа. Эти два метода служат резервными копиями или используются для регистрации новых устройств.
Бумажные ключи (вдохновленные RFC 1751 и BIP-39) — это ключи, удобные для чтения человеком, которые используются для безопасного хранения «идентификатора пользователя» на сервере. Бумажный ключ состоит из 12 случайных слов, выбранных из списка в 2048 слов, что обеспечивает энтропию в 121 бит (первое слово используется в качестве метки). Для шифрования «идентификатора пользователя» с помощью бумажного ключа система сначала выводит ключ шифрования, используя PBKDF2 для увеличения стойкости бумажного ключа до 256-битного ключа AES-GCM.
Создание зашифрованного поста
Для создания нового поста пользователь (его браузер) выполнит следующие действия:
-
подпишет содержимое текущего поста своим закрытым ключом подписи;
-
сгенерирует новый «ключ темы» (ключ AES-256-GCM) — он будет использоваться для шифрования поста, некоторых метаданных поста и названия новой темы (если доступно);
-
получит открытые ключи всех участников и зашифрует «ключ темы» для каждого из них;
-
отправит на сервер зашифрованный пост (в кодировке Base64) и зашифрованные ключи темы (также в кодировке Base64) для каждого участника.
Псевдокод операции шифрования может выглядеть следующим образом:
signature = rsa_pss_sign(current_user.identity.sign_key.private, post.raw) # 1
topic_key = topic.key || generate_aes_256_gcm_key() # 2
encrypted_title = aes_256_gcm_encrypt(topic.title, topic_key) if topic.blank?
encrypted_post = aes_256_gcm_encrypt(signature + post.raw, topic_key)
encrypted_topic_keys = recipients.map { |r| rsa_oaep_encrypt(topic_key, r.identity.encryption_key.public) } # 3
$.put("/posts/create", { title: encrypted_title, raw: encrypted_post, keys: encrypted_topic_keys }) # 4
Чтение зашифрованного поста
Для чтения поста пользователь (его браузер) выполнит следующие действия:
-
получит зашифрованный payload поста (текст поста и подпись) и зашифрованный ключ темы;
-
использует свой закрытый ключ шифрования для расшифровки зашифрованного ключа темы;
-
использует расшифрованный ключ темы для расшифровки зашифрованного payload поста;
-
получит открытый ключ подписи автора и проверит подпись поста.
Набор алгоритмов
Этот плагин активно использует криптографические примитивы, реализованные в Web Crypto API, которые доступны в любом из современных браузеров, поддерживаемых Discourse (кроме Internet Explorer).
-
getRandomValuesГПСЧ: Генерирует бумажные ключи и 96-битные случайные векторы инициализации (IV). -
PBKDF2: Увеличивает стойкость 132-битных бумажных ключей до 256-битных ключей, используемых для шифрования «идентификаторов пользователей».
-
AES-256-GCM: Используется для шифрования содержимого каждого поста. Также обеспечивает аутентификацию, создавая тег аутентификации длиной 128 бит, но это менее важный аспект, так как посты проверяются с помощью подписи, созданной автором (см. шаг 1 выше).
-
RSA-OAEP: Используется для шифрования «ключей тем» и «идентификаторов пользователей» для безопасного хранения на сервере. Все ключи RSA-OAEP имеют длину 4096 бит.
-
RSA-PSS: Используется для подписи содержимого каждого поста для проверки подлинности. Все ключи RSA-PSS имеют длину 4096 бит.
Примитивы
Система использует набор примитивов, построенных поверх тех, что предоставляются браузером через Web Cryptography API.
-
encrypt и decrypt: Используются для шифрования и расшифровки содержимого постов.
encryptпринимает JSON, ключ AES-256-GCM и открытый ключ RSA-PSS и выводит одну строку в кодировке Base64;decryptпринимает строку в кодировке Base64 и ключ AES-256-GCM и выводит исходный объект JSON; -
verify: Используется для проверки содержимого поста после расшифровки;
-
exportKey и importKey: Используются для экспорта и импорта «ключей тем»;
-
exportIdentity и importIdentity: Используются для экспорта и импорта «идентификаторов пользователей».
Типы ключей:
-
ключи тем (AES-256-GCM)
- используются для шифрования каждого поста в теме (посты шифруются индивидуально)
- генерируются для каждой темы на стороне клиента автором поста с использованием примитива API
generateKeyWebCrypto - шифруются открытым ключом пользователя для каждого пользователя, имеющего доступ к конкретной теме, с использованием примитива API
wrapKeyWebCrypto - хранятся (в зашифрованном виде) на стороне сервера для каждого пользователя в
PluginStore
-
пара ключей RSA (открытый и закрытый ключи) (RSA-OAEP и RSA-PSS, 4096 бит)
- используются для шифрования всех ключей тем, к которым имеет доступ пользователь
- генерируются для каждого пользователя на стороне клиента автором поста с использованием примитива API
generateKeyWebCrypto и разделяются между всеми устройствами пользователя - на стороне сервера: открытый идентификатор хранится в экспортированном виде, но закрытый идентификатор всегда будет зашифрован с помощью ключа-пароля
- на стороне клиента: открытые и закрытые ключи хранятся как
CryptoKeyв IndexedDb; если это невозможно, используетсяwindow.localStorage(в Safari)
-
ключи-пароли (выводятся с использованием PBKDF2 с 128 000 итерациями)
- используются для шифрования «идентификаторов пользователей» для безопасного хранения на сервере
- выводятся из бумажного ключа (или пароля пользователя для обратной совместимости)
Модели угроз
Скомпрометированный экземпляр Discourse
Атакующий, способный внедрить код, теоретически может получить доступ к зашифрованной информации, предоставив вредоносный код, который расшифровывает зашифрованное содержимое и отправляет текстовые посты на другой сервер. Для этого достаточно иметь доступ к учетной записи администратора и создать компонент темы с вредоносным кодом.
Механизмы защиты по умолчанию, такие как CSP (Content Security Policy), могут обнаруживать и смягчать атаки межсайтового скриптинга (XSS), которые также могут представлять собой способ внедрения вредоносного кода.
Атака «Человек посередине»
При атаках «Человек посередине» атакующий перехватывает связь между пользователем и сервером, что дает ему возможность читать или изменять ее. Поскольку плагин шифрует все данные перед отправкой, атакующий не может расшифровать ничего, просто подслушивая передачу. Аналогично, поскольку информация аутентифицирована, атакующий не может ее изменить.
Однако атакующий может предоставить вредоносный код обратно пользователю и провести атаку, аналогичную описанной в предыдущем разделе. Это частично смягчается использованием HTTPS, что значительно снижает вероятность атаки.
Примечания
У плагина уже есть небольшая история, что можно увидеть, просматривая исходный код и замечая две реализации протокола v0 (первоначальная альфа-бета версия) и v1. Протокол v0 больше не используется для шифрования новых постов, но сохраняется для продолжения расшифровки старых. Новый протокол включает аутентификацию шифротекстов, и все посты подписываются закрытым ключом автора.
