Original Plugin Description
| 概要 | Discourse Encrypt は、エンドユーザー間のプライベートで暗号化されたメッセージングを可能にします。すべての機密情報はサーバー上で安全に保存され、クライアント側でのみ暗号化および復号化されます。 | |
| リポジトリリンク | https://github.com/discourse/discourse-encrypt | |
| インストールガイド | Discourseでのプラグインのインストール方法 |
このプラグインを使用するための3つの簡単なステップ
- 暗号化を有効にし、現在のデバイスをアクティブ化します。
- 暗号化メッセージを送信します。受信者も暗号化を有効にする必要があります。
オプションで、メッセージ全体または特定の投稿が完全に削除されるまでの時間を指定できます。
- 秘密のメッセージを読む。それらを読むには、まず暗号化をアクティブにする必要があります。
注: この例では、ユーザーは暗号化が非アクティブ化されたため(ログアウトするか、設定画面から明示的に無効にしたため)、再度ペーパーキーの入力を求められました。
技術情報
このプラグインは、エンドツーエンドの暗号化スキームを使用して、Discourseを通じてユーザーが安全に通信できるようにします。プラグインのロジックの大部分はクライアント側で実装されており、サーバー側は公開情報または暗号化された情報のみを処理します。投稿のメタデータ(会話の参加者名、投稿時刻、いいね、小さなアクションなど)は暗号化されません。アップロードは暗号化されますが、その存在は暗号化されません。システムは、アップロードを削除しないように投稿に関連付ける必要があるためです。
すべてのコードはオープンソースであり、セキュリティ愛好家はそれをレビューすることを歓迎します。詳細については、私またはチームにお問い合わせください。 ![]()
read more...
概要
このプラグインの目標は、暗号化されたコンテンツの整合性と機密性を提供し、情報漏洩や不正なユーザーから保護することです。以下のセクションでは、通常の動作モード、使用されるアルゴリズム、脅威モデルについて説明します。
このシステムを使用するには、ユーザーは一度だけ登録する必要があります。これには、暗号化用と署名用の2つの4096ビットRSAキーで構成される「ユーザーID」を生成することが含まれます。ユーザーは、安全な保管のために「ID」をエクスポートするか、ペーパーキーを生成した後にサーバーに保存することができます。これらの2つの方法は、バックアップとして使用するか、新しいデバイスを登録するために使用されます。
ペーパーキー(RFC 1751とBIP-39に触発されています)は、人間が読み取り可能なキーであり、「ユーザーID」をサーバー上で安全に保存するために使用されます。ペーパーキーは、2048語のリストから選択された12のランダムな単語で構成され、121ビットのエントロピーを提供します(最初の単語はラベルとして使用されます)。「ユーザーID」をペーパーキーで暗号化するために、システムはまず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
暗号化された投稿の読み取り
投稿を読むには、ユーザー(ブラウザ)は次の手順を実行します:
-
暗号化された投稿ペイロード(投稿のプレーンテキストと署名)と暗号化されたトピックキーを取得します;
-
秘密暗号化キーを使用して暗号化されたトピックキーを復号化します;
-
復号化されたトピックキーを使用して、暗号化された投稿ペイロードを復号化します;
-
投稿者の公開署名キーを取得し、投稿の署名を検証します。
アルゴリズムスイート
このプラグインは、Web Crypto APIで実装された暗号化プリミティブを広く使用しており、これはDiscourseがサポートする最新のブラウザ(Internet Explorerを除く)のいずれかで利用可能です。
-
getRandomValuesPRNG: ペーパーキーと96ビットのランダムIVを生成します。 -
PBKDF2: 132ビットのペーパーキーを256ビットのキーにストレッチし、「ユーザーID」の暗号化に使用します。
-
AES-256-GCM: 各投稿のコンテンツを暗号化するために使用されます。また、128ビットの認証タグを生成することにより認証を提供しますが、これは投稿が投稿者によって生成された署名を使用して検証されるため(上記の手順1参照)、あまり重要ではありません。
-
RSA-OAEP: 「トピックキー」と「ユーザーID」をサーバー上で安全に保管するために暗号化するために使用されます。すべての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: 復号化後の投稿コンテンツの検証に使用されます。
-
exportIdentityおよびimportIdentity: 「ユーザーID」のエクスポートとインポートに使用されます。
キーの種類:
-
トピックキー(AES-256-GCM)
- 各投稿を暗号化するために使用されます(投稿は個別に暗号化されます)
- 生成は、クライアント側で元の投稿者によってWebCryptoのAPI
generateKeyプリミティブを使用してトピックごとに生成されます - 暗号化は、特定のトピックにアクセスできるすべてのユーザーに対して、ユーザーの公開キーを使用してWebCryptoのAPI
wrapKeyプリミティブで行われます - 保存は、
PluginStore内の各ユーザーに対してサーバー側(暗号化された状態)で行われます
-
RSAキーペア(公開キーと秘密キー)(RSA-OAEPおよびRSA-PSS、4096ビット)
- ユーザーがアクセスできるすべてのトピックキーを暗号化するために使用されます
- 生成は、クライアント側で元の投稿者によってWebCryptoのAPI
generateKeyプリミティブを使用してユーザーごとに生成され、ユーザーのすべてのデバイス間で共有されます - サーバー側: 公開IDはクライアントによってエクスポートされた状態で保存されますが、秘密IDは常にパスフレーズキーで暗号化されます
- クライアント側: 公開キーと秘密キーはIndexedDbに
CryptoKeyとして保存されます。不可能な場合は、window.localStorage(Safari)を使用します
-
パスフレーズキー(PKBDF2を使用して128,000回の反復で導出)
- 「ユーザーID」をサーバー上で安全に保管するために暗号化するために使用されます
- ペーパーキー(またはレガシー目的のユーザーのパスフレーズ)から導出されます
脅威モデル
侵害されたDiscourseインスタンス
コードを注入できる攻撃者は、理論的には、悪意のあるコードを提供して暗号化されたコンテンツを復号化し、プレーンテキストの投稿を別のサーバーに送信することで、暗号化された情報にアクセスできます。これを実現するには、管理者アカウントにアクセスして、悪意のあるコードを含むテーマコンポーネントを作成するだけで十分です。
CSPなどのデフォルトの保護メカニズムは、悪意のあるコードを注入する方法にもなり得るクロスサイトスクリプティング(XSS)攻撃を検出し、緩和できます。
中間者攻撃
中間者攻撃では、攻撃者はユーザーとサーバー間の通信を傍受し、それを読み取ったり変更したりする能力を得ます。プラグインは送信前にすべてを暗号化するため、攻撃者は単に盗聴するだけでは何も復号化できません。同様に、情報が認証されているため、攻撃者はそれを変更することはできません。
ただし、攻撃者は悪意のあるコードをユーザーに提供し、前のセクションで提示された攻撃と同様の攻撃を行う可能性があります。これはHTTPSによって部分的に緩和され、攻撃の確率が大幅に減少します。
注記
プラグインにはすでに少しの歴史があり、ソースコードを閲覧してプロトコルの2つの実装 v0(初期、アルファベータリリース)と v1 に気づくことで確認できます。プロトコル v0 は新しい投稿の暗号化には使用されなくなりましたが、古い投稿の復号化を続けるために保持されています。新しいプロトコルには、暗号文の真正性が含まれ、すべての投稿は投稿者の秘密キーで署名されます。
