信頼性の低いサーバーがユーザーの機密データ(クライアント側で暗号化)を格納するために使用され、認証と暗号化/復号化の両方のタスクが単一のパスワードで実行可能であるとします。それで十分でしょうか?
[1]
を使用してパスワードを強化し、k
を生成します。k
をSRPの「パスワード」として使用し、サーバーで認証して暗号文を受信します。悪意のあるサーバー(リスクが低い)はk
を取得するために、オフラインの辞書攻撃 検証者に対して または暗号文に対して-を実行する必要がありますが、外部の攻撃者(リスクが高い)はデータベースのコピーを取得しない限り、オンライン攻撃を実行できます(ベリファイアにも暗号文にもアクセスできないため)。これは、サーバーの同様の状況に置かれるだけです[2]
。
この推論は正しいですか?予想していなかった欠陥はありますか?いくつかのメモ:
私の懸念の1つは、特定のユーザーをターゲットにしたRainbowテーブルを攻撃者が作成し、データベースを取得して、そのユーザーとしてほぼ即座にログインできることです。候補となるパスワードのリストではなく、キー(キーになる前に拡張する必要があります)。
もちろん、攻撃者が(パスワードが弱い場合の)計算能力を持っている場合、漏洩した暗号文は最終的に解読されますが、サーバーがこのシナリオに対して強力である場合(SRPについて学習する前に、私が設計した- より複雑なプロトコル これを考慮に入れましたが、より無駄が多く、未解決の質問がありました)。
健康上の注意の練習として、私は次のことをアドバイスします。
ユーザーパスワードからキーk
を取得する場合は、キーを長くして、2つに分割します。前半はSRPに使用し、後半は暗号化に使用します。これを達成する簡単な方法は、SHA-256でk
をハッシュし、256ビットを生成して、2つの細かい128ビットキーに分割することです。または、 PBKDF2 のように、出力サイズを調整可能な 鍵導出関数 を使用します。
ここでの要点は、対称暗号化とSRPで実行される計算との間の、望ましからぬものですが、望ましくない「相互作用」を回避したいということです。 2つのサブキー間で一方向性の層を挿入すると、このような問題を防ぐことができます(SHA-256が多かれ少なかれ ランダムOracle のように動作すると想定)。
ある理由で暗号化します。その後、攻撃者が対称的に暗号化されたデータBLOBを観察する可能性があると想定する必要があります。そうでなければ、暗号化のポイントは何でしょうか?しかし、そのような盗聴が可能な場合は、塩が適切である必要があります。すべてのユーザーが同じソルトを使用し、攻撃の最適化(つまり、レインボーテーブル)を可能にするため、空のソルトはそれをカットしません。
ここで興味深い点があります。それは、SRP自体に塩処理が含まれていることです。 SRPをTLSハンドシェイクに統合する方法を説明する RFC 5054 をよく見てください。最初のステップでは、クライアント(ClientHello
内)がユーザーのID(I
)を送信します。サーバーは、salt ServerKeyExchange
を(他の値とともに)含むs
を含むいくつかのメッセージで応答します。つまり、ここに、「ソルトを要求するすべての人にソルトを送信するサーバー」があります。
SRPでの実際のパスワード処理は、x = SHA1(s | SHA1(I | ":" | P))
の計算です。これはソルト付きですが、十分に反復されていないパスワードハッシュ関数です。これは現在定義されているSRPの既知の問題です。ただし、クライアントとサーバーが同意する限り、この操作を 強力なパスワードハッシュ関数 に置き換えるのは簡単です。
これにより、次のスキームが得られます。
P
を選択し、ランダムなソルトs
が生成されます(たとえば、暗号学的に強力なPRNGから128ビット)。P
とs
から、強力なパスワードハッシュ関数( bcrypt など)が適用され、中間値z
が生成されます。 SHA-512の場合、512ビットになります。これらの512ビットは2つの256ビットの半分に分割されます。前半はSRPのx
値であり、後半(y
と呼ぶ)は対称暗号化に使用されます。I
)をサーバーに送信し、salt s
を取得します。 x
とy
の同じ計算が再度行われます。 x
部分はSRPに使用され、y
部分はサーバーに格納されているblobを復号化するために使用されます。このスキームは、上記のすべてのポイントを組み合わせたものです。パスワードからキーへの派生では、適切な関数を適切なランダムソルトで使用します。パスワードの2つの使用法の間にSHA-512の分離層があります。基本的なSRPと比較して、追加のメッセージ交換は必要ありません。実際、ここで提案するのは、SRPで行われるパスワードハッシュの強化であり、対称暗号化のニーズに合わせてパスワードから派生したキーを追加でリーチングすることです。
最初にSSL/TLSトンネルを確立してからSRPを実行することもできますが、RFC 5054の道に従って、TLSハンドシェイクにSRPを使用することもできます。ここでは、SRP実装を含むクライアントコードとサーバーコードの両方を制御する必要があります。ここでは、パスワードからキーへの派生プロセスを変更する(つまり、強化する)ことを提案しているからです。これに対応して、クライアントは必要なコードをすでに持っている必要があります。 Web-Javascriptのコンテキストでは、最初に「通常の」SSL/TLSが必要になりますが、その時点でSRPの利点は非常に小さくなります。
SRPに固有のように、サーバーがソルト値を誰にでも要求できるようにすることは、重大な問題ではありません。塩は秘密を必要としません。ソルト値を秘密に保つことは害ではありませんが、これは二次的な目標にすぎません。塩の主なポイントはuniquenessです。秘密の不当なかゆみを独自性の道に入れないでください。
ここでは、データがキーk
(SRPパスワードと同じ値)を使用して暗号化されていると想定します。これを指定しなかったので、これが意図したものと異なる場合は、質問を編集してください。
はい、これは合理的なスキームです。
可能であれば、ユーザーのユーザー名とサーバーの識別子(ドメイン名など)を、遅い鍵導出関数へのソルトとして使用することをお勧めします。また、パブリックでユーザーごとに異なるランダムな値にすることもできます。
Rainbowテーブル: Rainbowテーブルを作成するコストは、多数の候補パスワードを試すのと同じくらいかかるため、Rainbowテーブルは攻撃者にあまり役立ちません。レインボーテーブルは、複数回攻撃している場合(複数のユーザーを攻撃している場合など)、コストを償却したい場合にのみ役立ちます。一部のユーザー名が非常に一般的であると思われる場合(例:alice
)、それはwouldalice
に固有のRainbowテーブルを作成することが可能です(1回限りの計算)そして、それらすべてのサーバーにalice
という名前のアカウントがあることを期待して、それを使用して複数のサーバーを攻撃します。ただし、これにより速度が向上するのは、(おそらく、複数の異なるサーバー上で)同じユーザー名を持つ複数のユーザーが見つかった場合のみです。実際にはそれほど脅威ではないと思います。気になる場合は、ユーザーごとに異なるランダムな値をソルトとして使用するか、ユーザーのユーザー名とサーバーの識別子の組み合わせをソルトとして使用することで回避できます。
その他:最大の弱点は、おそらくクライアントが暗号文を復号化するコードを取得するところです。これがクライアント側の専用アプリケーションである場合は、クライアントプログラムのコードに組み込むことができます。しかし、クライアントがWebブラウザーを介して一部のWebサイトにアクセスしていて、復号化コードがサーバーによってJavascript(たとえば)として提供されている場合、悪意のある/侵害された/なりすましサーバーは、ユーザーのパスワードを盗む悪意のあるJavascriptを送信できます。
あなたが検討したいと思うかもしれない別のアプローチがあります。ユーザーパスワードpを取得し、saltを適用し、それをキー導出を通じてプッシュして、より長いキーkを生成します。次に、kを2つの部分aとbに分割します。最初の部分aはデータの暗号化に使用され、2番目の部分bはサーバーへの認証に使用されます。
使いやすさとセキュリティ要件を満たしていますか?