エンドユーザー間のプライベートで暗号化されたメッセージングを可能にするプラグインの委託をご希望です。
このプラグインは現在存在し、公式にサポートされています。詳細は Discourse Encrypt (deprecated) をご覧ください。
現状、安全でプライベートな長文コミュニケーションのためのオンライン手段は極めて限られています。既存のツールは非常に難解で、使用するには高度な技術スキルが要求されます。その結果、大多数の「プライベート」なコミュニケーションは、Telegram、Skype、WhatsApp などの「短文」形式で行われています。さらに、この大量コミュニケーションのモードは、クローズドソースのツールやクローズドソースのプロトコルに依存しているため、適切に監査可能ではありません。
私たちは、専用の Discourse プラグインとして、使いやすく監査可能な暗号化メッセージングソリューションを構築したいと考えています。
これを実現するために、以下の原則に基づいて構築します。
- Web Crypto API を基盤としてソリューションを構築する
- サーバーにユーザーごとに暗号化された秘密鍵と公開鍵を保存する
- サーバーにプライベートメッセージの各参加者ごとに暗号化された会話鍵を保存する(エンドユーザーの秘密鍵を使用して暗号化)
- すべての Markdown とタイトルを、メッセージごとに**生(raw)**の暗号化形式で保存する(会話鍵を使用して暗号化)
- サーバーが「誰が、いつ、誰と話したか」を知っているという制限を受け入れる(守るのは「何を」話したかだけ)。また、このコンテンツに対する検索機能は動作しないという制限も受け入れる。
提案されるエンドユーザー体験
Jane がユーザーページにアクセスし、「暗号化メッセージを有効化」ボタンをクリックします。クリックすると秘密の入力を求められます。UI は、この秘密を忘れた場合、暗号化されたメッセージに決してアクセスできなくなることを明確に説明します。
暗号化メッセージが有効化されると、メッセージ作成 UI に新しい [ ] が表示され、テキストは [ ] メッセージを暗号化 となります。これは、すべての受信者が「暗号化メッセージ」を有効にしている場合にのみクリック可能です。一部の受信者が公開鍵を持っていない場合、クリックしようとした際に「申し訳ありませんが、一部の参加者に暗号化メッセージが有効化されていません」と表示されます。
Jane は Pete と非公開で話したいと考え、参加者リストに彼を追加し、メッセージを暗号化 をクリックして Pete にメッセージを送信します。
Pete は Jane からの暗号化メッセージが届いたという通知を受信します。タイトルはなく、暗号化されたメッセージが存在することと、そのメッセージへのリンク(メール通知と Web 通知の両方)だけが表示されます。
Pete が暗号化メッセージを有効にした元のデバイスにいれば、秘密のパスフレーズは既に入力されており、認証情報は IndexedDB に保存されています。Pete が新しいデバイスにいれば、暗号化メッセージを有効にするために秘密のパスフレーズの入力を求められます。
UI は、メッセージが暗号化されていることを示すオーバーレイまたは視覚的なヒントを明確に表示します。
Jane と Pete の間でコミュニケーションが始まると、いずれかの参加者が公開鍵を持っている限り、新しい人をそのメッセージに招待できます。
Pete も Jane も、いつでも秘密のパスフレーズを変更できます。変更した場合、秘密鍵は新しいパスフレーズを使用して再暗号化され、サーバーへ送信されます(V1 では、実際の秘密鍵の変更ではなく、パスフレーズの変更のみを許可します)。
技術的な詳細
いかなる時点でも、暗号化されていないプライベートな会話や認証情報がサーバーに送信されることはありません。サーバーに対して信頼を置く唯一の点は、クライアントに送信される JavaScript ペイロードが改ざんされていないことです。
秘密鍵と公開鍵のペアは 100% クライアント側で生成され、その後、秘密鍵は AES 対称暗号化を使用して暗号化され、サーバーへの安全な保管のために渡されます。パスフレーズは、サーバーに保存されたランダムに生成されたソルトを使用してストレッチ(伸長)されます。キーストレッチは、クライアント側で PBKDF2(Web Crypto API で利用可能)を使用して行われます。秘密鍵/公開鍵のペアは、エクスポート不可能な CryptoKey オブジェクトとしてクライアントの IndexedDB に保存されます。エクスポート可能な CryptoKey データは、可能な限り速やかにメモリから削除されます。
暗号化された秘密鍵と公開鍵は、ユーザーのカスタムフィールドに保存されます。暗号化された秘密鍵の読み書きが許可されるのは current_user のみであり、すべてのログインユーザーは全ユーザーの公開鍵の読み取りを許可されます。
会話鍵は、会話の開始時または招待時にクライアント側で生成され、会話に関与するすべての公開鍵を使用して暗号化されます。このデータは専用テーブル (user_id, topic_id, encrypted_conversation_key) に保存され、この行は会話内の任意のユーザーによって作成可能ですが、current_user == user_id の場合にのみ読み取り可能です。
下書きが暗号化されていない状態で保存されないようにするなど、暗号化されていないデータがサーバーに漏洩することのないよう特別な注意を払います。
広範なエラーを回避するため、作曲器(composer)の編集とプレビューには新しい DOM 要素(新しい ID を持つ)を使用します。現在の .d-editor-input には常に暗号化されたブロブのみが含まれ、従来のプレビューは無効化されます(つまり、暗号化用と非暗号化用の 2 つのテキストエリアが使用されます)。パフォーマンス上の問題を防ぐため、暗号化処理は大幅にデバウンス(遅延実行)されます。
V1(およびこの作業項目の範囲)では、アップロード機能、暗号化コンテンツのワンボックス化、その他の複雑なエッジケースなどの特定の機能を排除することに問題ありません。
このプライベートコンテンツをレンダリングする際、HTML をホワイトリストでフィルタリングしながら、その場で復号化/生成して渡すことは問題ありません。
ドキュメント要件
実装に先立ち、Web モックアップを含む非常に詳細な仕様書、そして最も重要となる詳細なセキュリティ概要を作成します。
テスト要件
このプラグインには、クライアント側およびサーバー側に基づく包括的な単体テストおよび結合テストが含まれている必要があります。このプロジェクトを受託される場合は、テストを早期に作成し、プロジェクトが終了してからテストを後付けするよう待たないでください。
懸念事項
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/ に記載されている多くの懸念事項は、Web Crypto API(真の乱数バイト生成、秘密鍵の保存など)の登場により、もはや関連性がありません。存在する主要な攻撃ベクトルは、サーバーがクライアントに悪意のある JavaScript を送信するケースのみです。短期的には、ユーザーは 1Password、LastPass、その他の Web セキュリティ UI を信頼するのと同じように、サーバーを信頼することが期待されます。長期的には(v3/v4、来年以降)、すべての JS ペイロードの安定性ハッシュが既知であるサイトに鍵マークを表示するブラウザ拡張機能の提供を検討できます。
WebCrypto API は比較的新しいですが、広くサポートされており、このプラグインはサポート対象のすべてのブラウザで動作する必要があります。
シンプルなラフモックアップ
* メッセージ開始時、ユーザーは会話を暗号化するオプションを選択できます。参加者のいずれかが公開鍵を持っていない場合、警告が表示されます。
* ユーザーは、そのボタンをクリックして鍵ペアを生成する UI を介して、暗号化メッセージを有効にできます。
暗号化メッセージが有効化されている場合、単に「暗号化メッセージが有効になっています」と表示されます。
* 何らかのアイコンまたはオーバーレイで、メッセージが暗号化されていることを示します。
予算
これは、非常に深い統合と慎重なレビューを必要とする非常に複雑な開発です。クライアント側およびサーバー側の両方を使用したテストが極めて十分に行われていることを期待しています。MVP(最小実行可能製品)の現在の予算は 10,000 米ドルです。


