5

Wall-O-Textの受信について、あらかじめお詫び申し上げます。これは(少なくとも私にとっては)かなり複雑な問題であり、私はかなりのことを考えてきました。私の質問を読んだり、このGitHub GistでRubyのテスト実装(非常に急いで構築され、データベースにバックアップされておらず、おそらく非常に醜い)を見ることができます。


序章

次の要件を持つWebベースのパスワード管理システム(SSL経由!:)を作成する必要があると想像してください。

  1. 個々のユーザーは、独自のパスフレーズを使用してシステムにサインインします。
  2. このパスフレーズは、ユーザーがシステムを効果的に使用できるようにするために十分なものである必要があります(たとえば、スマートフォンなどから)。つまり、キーファイルを保持する必要はありません。
  3. ユーザーは、任意の長さのデータをシステム(「エントリ」)に保存できます。
  4. エントリは、暗号化されたエントリを読み取るのに十分な情報がデータベースまたはアプリケーションだけにないように、データベースで暗号化されます。
  5. ユーザーは、他のユーザーがエントリの内容を読み取れるように、システムの他のユーザーとエントリを「共有」できる必要があります。

私は暗号化の専門家ではありません。しばらく考えてみたところ、次のことが思い浮かびました。 私の質問は:この実装は安全ですか?私は何かが足りないのですか?もしそうなら、上記の仕様は実装可能ですか?それともこれはやり過ぎですか?

データベース

データベースは次のように設定されます。

+------------------------------------------------------------------------------+
|  users                                                                       |
+---------+--------------+--------------+---------------+----------------------+
| salt    | pub_key      | enc_priv_key | priv_key_hmac |                      |
+---------+--------------+--------------+---------------+----------------------+
|  entries                                                                     |
+---------+--------------+--------------+---------------+----------+-----------+
| user_id | parent_entry | enc_sym_key  | sym_key_sig   | enc_data | data_hmac |
+---------+--------------+--------------+---------------+----------+-----------+

基本的なユースケース

システムの2人のユーザー、アリスとボブを想像してみましょう。

ボブはサイトにサインアップします

  • ボブはパスワードを入力します。このパスワードはサーバーに送信されます(ただし、保存されません)。
  • サーバーはランダムなソルトを生成し、それをsaltフィールドに保存します。
  • サーバーは、ボブのパスワードとソルトのSHA-256ハッシュを生成します。
  • サーバーはRSAキーペアを生成します。公開鍵は、フィールドにプレーンテキストとして保存されpub_keyます。秘密鍵は、ボブのパスワードとソルトから生成されたハッシュを鍵として使用してAES-256を介して暗号化され、enc_priv_keyフィールドに保存されます。
  • サーバーは、ボブのパスワードとソルトをキーとして使用して、ボブの秘密キーのハッシュベースのメッセージ認証コードを生成し、これをpriv_key_hmacフィールドに格納します。

ボブはシステムにエントリを保存します

  • ボブは、パスワードとともにエントリとして保存するデータを入力します。このデータはサーバーに送信されます。
  • サーバーは、AES-256暗号化のキーとして使用されるキーを生成します。
  • サーバーはこのキーを使用してデータを暗号化し、結果をenc_dataフィールドに保存します。
  • サーバーは、生成されたキーを使用してデータのハッシュベースのメッセージ認証コードを生成し、これをdata_hmacフィールドに格納します。
  • データの暗号化に使用される対称鍵は、ボブの公開鍵で暗号化され、enc_sym_keyフィールドに保存されます。
  • サーバーはBobの秘密鍵を使用して、対称鍵の署名を生成します。

ボブは保存されたエントリを取得します

  • ボブは自分のパスワードと取得するエントリのIDを入力します。
  • サーバーは、ボブのパスワードとソルトのSHA-256ハッシュを生成します。
  • ボブの暗号化された秘密鍵は、ハッシュを使用したAES-256暗号化によって復号化されます。
  • サーバーは、でHMACをチェックすることにより、ボブの暗号化された秘密鍵が改ざんされていないことを確認しpriv_key_hmacます。
  • サーバーは、enc_sym_keyボブの秘密鍵を使用して、フィールドに格納されている対称鍵を復号化します。
  • sym_key_signサーバーは、ボブの公開鍵を使用して署名を検証することにより、暗号化された対称鍵が改ざんされていないことを検証します。
  • サーバーは、対称鍵を使用してデータを復号化します。
  • サーバーは、フィールドに格納されているHMACを検証することにより、暗号化されたデータが改ざんされていないことを検証しdata_hmacます。
  • サーバーは復号化されたデータをボブに返します。

ボブはアリスとエントリを共有します:

  • ボブは、アリスが自分が所有するエントリにアクセスできるようにしたいと考えています。彼は自分のパスワードと共有するエントリのIDを入力します。
  • エントリのデータは、「ボブが保存したエントリを取得する」の方法を使用して復号化されます。
  • 次の例外を除いて、「ボブがシステムにエントリを格納する」と同じ方法で、アリスの新しいエントリが作成されます。
    1. エントリparent_entryはボブのエントリに設定されます。
    2. 対称鍵の署名は、ボブの秘密鍵を使用して計算されます(アリスの秘密鍵はボブが使用できないため)。
    3. アリスがこの新しいエントリにアクセスすると、null以外が存在する parent_entryと、システムはボブの公開鍵を使用して署名を検証します(彼の秘密鍵が署名の作成に使用されたため)。

ボブは共有エントリのデータを変更します

  • ボブは、アリスと共有したエントリのデータを変更することにしました。ボブは、変更するエントリIDとそれに含める必要のある新しいデータを示します。
  • 「ボブはシステムにエントリを保存します」で作成されたデータを上書きします。
  • parent_entryシステムは、変更されたばかりのエントリと等しいすべてのエントリを検索し、それぞれについて、「ボブはアリスとエントリを共有します」で作成されたデータを上書きします。

分析

利点:

  • データを復号化するために必要な秘密鍵はユーザーのパスワードで暗号化され、そのパスワード(およびそのハッシュ)はに保存されないため、データを所有するユーザーのパスワードなしでデータベースからデータを復号化することはできません。データベース。
  • ユーザーがパスワードを変更したい場合は、暗号化された秘密鍵のみを再生成する必要があります(古いパスワード/ハッシュで秘密鍵を復号化してから、新しいパスワード/ハッシュで再暗号化します)。
  • 共有エントリは実際の個別のレコードとしてデータベースに保存されるため、複数のユーザー/ユーザーグループ間でキーを共有する必要はありません。

短所/問題(私が考えることができる):

  • 共有エントリが変更された場合、システムはすべての子エントリを再暗号化する必要があります。多数のユーザーがデータを共有している場合、これは計算コストが高くなる可能性があります。
  • 共有エントリは、署名の検証のために親ユーザーの公開鍵に依存します。ユーザーが削除された場合、またはユーザーのキーが変更された場合、署名は無効になります。

はじめに繰り返します:私の質問は:この実装は安全ですか?私は何かが足りないのですか?もしそうなら、上記の仕様は実装可能ですか?それともこれはやり過ぎですか?

これだけ長く突き出してくれてありがとう。あなたの意見に興味があります!私は正しい方向に進んでいますか、それとも完全なモロンですか?あなたが決める!:)

4

3 に答える 3

1

IVストレージはありませんか?AES-256-ECBを使用できると思いますが、ユーザーが保存できるのは32バイトのパスワードのみであり、生成された秘密鍵が1つの暗号化にのみ使用されるようにする必要があります。(現在の設計はこの点で安全に見えますが、32バイトを超えるパスワードを許可する場合、またはこのキーを2つの役割にすることを考えている場合は、暗号化ごとにIVを保存する必要があります。)

priv_key_hmacとのセキュリティ値がわかりませんdata_hmac。秘密鍵または暗号化されたデータのいずれかが改ざんされている場合、ガベージ出力は秘密鍵または対称鍵を使用した復号化の結果として発生します。BELボブは、キャラクターの入力方法がわからないときは、きっと疑わしいでしょう。:)(人間は出力を見ることがありますか?人間は、返されたパスワードが間違っていることに気付く可能性があります。コンピュータは違いを認識できなかったので、自動システムが結果のパスワードを使用する場合は、必ず保持してください。フィールド。)

「パスワードを忘れた」という仕組みはありません。パスワードを忘れた場合にデータを回復できないことをユーザーが知っていることを確認してください。最近のユーザーは甘やかされており、あなたのサービスにも甘やかされていることを期待するかもしれません。

ボブが復号化するエントリをユーザーが指定するメカニズムがわかりません。エントリごとに、名前、または名前のハッシュバージョンを保存する必要がありssh(1)ます。名前を直接保存するとSHA-256の操作が削除されますが、ユーザーがアカウントを持っているサービスのクリアテキスト名を報告するデータベースの侵害は、あらゆる点で損害を与える可能性があります。(おそらく、オンラインのエスコートサービス、オフショア銀行、またはファイトクラブです。)known_hosts

于 2011-03-27T08:30:08.570 に答える
1

アリスとエントリを共有する場合を除いて、実際に複製する必要はありませんenc_sym_key。対称鍵が複数のエントリに再利用されることはないため、暗号化されたデータのコピーが1つだけ必要です。

于 2011-03-28T05:21:11.423 に答える
0

ユーザー間でデータを共有するために証明書を使用してみませんか?ユーザーのPEMキーと秘密キーを保持するためにPKCS#12証明書を使用し、ユーザーごとまたはサイトごとにPEMを使用して、データの検証とセキュリティのために署名および暗号化できます。

説明するシナリオ。

ボブは、イブを読まずにアリスと共有したいと考えています。

アリスはボブに公開鍵を渡します。ボブは、信頼できるユーザーのキーチェーンにアリスの公開鍵を追加します。次に、ボブはアリスの公開鍵を使用してメッセージを暗号化し、自分のPEMを使用してデータに署名します。もちろん、このシナリオでは、署名の検証を実行するために、アリスがボブの公開鍵のコピーをすでに持っている必要がありますが、あなたはその考えを理解します。

また、なぜ塩や点滴を保存するのですか?データベースが侵害された場合、保存されているデータと一緒に保存されているこれらの両方にアクセスできます。

ベストプラクティス...

  1. 他の公開鍵/PEM証明書を保存するために、各ユーザーアカウントにキーリングを使用します
  2. アカウント間で情報を共有するには、公開鍵暗号化のみを使用してください
  3. アカウント間で共有されないユーザーの秘密鍵を使用してデータを暗号化する
  4. パスワードの保存にAES、RSA、またはその他の可逆暗号化を使用しないでください
  5. パスワードのハッシュアルゴリズムをさらに強化するためにユーザー固有のソルトを使用する必要があり、保存しないでください
  6. サイト全体のパスワードを使用したAESの使用は、セキュリティをさらに向上させるために静止データの保存に使用できます(ただし、CONSセクションで概説した問題が発生します)
于 2012-04-06T14:11:39.600 に答える