ランポートハッシュチェーン-顧客パスワードデータベースの盗難に対する保険

Habréで最近公開された非常に興味深い投稿 、特にそのコメントは、おそらく、サーバーからのパスワードデータベースの盗難に対して実際に保険を提供する唯一の対称スキームであるLamportハッシュチェーンについて説明するように促しました。 アルゴリズムは実際には非常に単純で、1981年に著者(L. Lamport)によって提案されました。 さらに、ほとんどの教科書のスキームはすでに「廃止」と呼ばれています。 開発の目的は、主に転送フェーズ中のパスワードの傍受から保護することでしたが、後のチャレンジハンドシェイク(CHAP、CRAM)ファミリースキームはこの問題をより効率的に解決します。 しかし、Lampportスキームの2番目の興味深いプロパティは徐々に忘れられています-サーバー側に保存されているユーザー認証データの機密性は必要ありません (通常、クライアント証明書を使用した非対称スキームにのみ固有のプロパティ)。 暗号化ハッシュ関数のみを使用してこのプロパティを実現する方法を見てみましょう。





正式なタスクの説明



暗号化の観点から問題を定式化します(脅威モデルの構築)。

A)サーバーは、クライアントの認証を可能にするデータを保存します。

B)このデータの開示/盗難により、攻撃者がサーバーの前でクライアントになりすますことはできません。

C)認証段階でクライアントとサーバー間で送信されるデータの開示/リスニング(複数を含む)(「プロトコルのリッスン」)により、攻撃者がこのクライアントになりすますことはできません。

D)アクティブな中間者攻撃者に対する保護のタスクは設定されていません。

E)サーバーをハッキングする場合、攻撃者は機密性のみに違反し、認証データベースの整合性には違反できないと考えています(整合性違反の事実は追加の制御メカニズムによって監視できます)。



メソッドの主なアイデア



認証データベースの盗難の場合、攻撃者がサーバーとまったく同じ情報を自由に使用できることは明らかです。 したがって、クライアントの信頼性をチェックするプロセスは、クライアントの有効性を検証でき、それを自分で渡すことができないように(クライアントに代わって)サーバーによって実行される必要があります。 データ(パスワード、暗号文など)の比較によってチェックすることにより、このプロパティを実現することはできません。 このチェックは、他の誰にもできないことを行うクライアントの能力(サーバーを含む)で実行する必要があります。 対称暗号化では、そのような変換は暗号化ハッシュを計算することだけです。



さて、今スキームの本質。



認証データを設定するプロセス

  1. クライアントとサーバーは、数N(たとえば、1.000から100.000の範囲)に同意します。この値は分類されておらず、単純にハードコーディングできます。
  2. クライアントは、大きな次元(128ビット以上)の乱数Pを選択します。

    -ユーザーのパスワードとサーバー名P = H(パスワード||サーバー名)からハッシュ関数を使用して計算します。

    -信頼できる乱数/擬似乱数のソースから生成して、その側面に保存します(欠点は、クライアントステーションへの「リンク」またはトークンを使用する必要があることです)。
  3. クライアントは、番号Pに対してHのN回の暗号暗号化ハッシュを実行し、結果の結果H(H(H(... H(P))))= H N (P)をサーバーへの変更から保護されたチャネル経由で転送します( 注意! 記事全体 の表記 H K (P) は、結果をKの累乗に上げるのではなく、ハッシュ関数の重ね合わせ(呼び出しのK倍の繰り返し)を示すために使用されます
  4. サーバーは、今後のクライアント認証のシーケンス番号のカウンターAを番号1で初期化します。


認証プロセス



次にユーザーの信頼性を検証する必要があるたびに:

  1. サーバーは申請者に番号Aを送信します。
  2. クライアントは、数Pで(NA)回ハッシュを実行し、結果の結果H NA (P)をサーバーに渡します。
  3. サーバーは、もう一度Aの数H NA (P)でハッシュを実行し、結果の結果H A (H NA (P))と保存されたH H(P)をチェックします。
  4. 結果が一致する場合、クライアントは認証を正常に確認したと見なされ、サーバーは認証成功のカウンターを1ずつ増やします。A= A + 1により、チェーンがに1つシフトされます。


ランプポートの基本設計



必須プロパティの証明



ランポートスキームに適用される要件B)およびC)は、基本的に1になります:カウンター値がAの場合、攻撃者はリストH N-A + 1 (P)から値のセット(おそらく完全なものを含む)を所有します。 H N-A + 2 (P)、...、H N (P)は、カウンター値A、またはAより大きい他の値に対して正常に認証できないはずです。これはそうですか? まず、上記のリスト全体の値は、攻撃者と1-H N-A + 1 (P)の最初の値に等しいことがわかります(残りは簡単に計算されるため)。 未知のPを持つH N-A + 1 (P)の知識は、H NA (P)を計算する機会を与えますか? このタスクは、既知の値から暗号化ハッシュ関数のプロトタイプを見つけるタスクであるため、間違いありません。 入力領域が十分に大きい場合、ハッシュ関数の暗号解析の最近の進歩にもかかわらず、この問題はまだ妥当な時間内に解決策がありません。



効果的な実施



安定性にまったく影響を与えない、スキームのかなり明らかな改善は、A操作の定数チェックを伴うH N (P)値ではなく、1つのハッシュ計算操作のみからのチェックを伴うH N-A + 1 (P)値をサーバー側に格納することです:H(H NA (P))? H N-A + 1 (P)。 このオプションでは、クライアントログインに成功するたびに認証データフィールドを更新する必要がありますが、カウンターAを更新する必要があるため、マイナスの影響ははるかに少なく、プラスはサーバーのCPUの負荷が急激に減少します。 A回のハッシュ計算の必要性はなくなります。



最後のハッシュのサーバー上のストレージ



スキームが提案された当時、ハッシュ関数の数千の値の計算は非常に計算が複雑なプロセスであると見なされていたため、クライアント側で改善が提案されました:H N (P)中間値の特定のステップでの初期計算の過程でのキャッシング。 これにより、クライアント応答の計算を高速化できましたが、キャッシュと同様に、長期保存用の追加リソースが必要でした(さらに、パスワードPに類似した機密性要件が提示されているはずです)。 最近では、弱いPCでもハッシュ関数の100,000回の繰り返しを計算するのに約1秒かかります。 したがって、このようなキャッシングは、最も弱いハードウェアプラットフォームに対してのみ推奨できます。



クライアントチェーンキャッシング



質問、問題、解決策



ランポートのスキームの主な問題は、もちろん、積極的な攻撃者(「中間者」)です。 明らかに、クライアントが応答する前に、サーバー認証がない場合、攻撃者は、おそらくサーバーに代わって、意図的に大きいカウンター値Aを送信すると、クライアントから値H N-A ' (P)を受信し、範囲H N-A'から任意の値を計算できます(P)... H NA (P)。 サーバーを監視するためのいくつかのソースのクライアントの現在のカウンターA値のストレージは、実際に問題を解決しません。なぜなら、攻撃者仲介者の脅威を受け入れた場合、彼は依然として正しいクライアントパケットH NA (P )、すでにあなたのステーションからの助けを借りて認証します。



同じ理由で、この脅威モデルでは、一部の実装で提案されているように、成功したかどうかに関係なく、認証要求のカウンターAを増やすことは意味がありません。 このスキームは、攻撃者によるカウンターの枯渇(DoS)の脅威をもたらしますが、中間の攻撃者からはまだ保護されません。 原作の著者自身は、失敗した試行でカウンターを変更することを推奨していません。



現在、SSL(クライアントに対する一方向サーバー認証)は、両方の脅威に対する最適な保護を提供できます。 繰り返しになりますが、サーバーの前で証明書を使用してクライアント認証を行う「双方向」SSLは、もちろん、一般的なパスワード盗難の問題全体を解決します。 しかし、多数の顧客での展開とサポートの両方で1桁重いです。 ここで、すべての問題は、適切に署名されたサーバー証明書を持つ「一方向」のSSLによって正確に解決できます。これにより、クライアントは正当なサーバーにのみ次のH K (P)値を報告できます。



リカバリスキームが0より大きいRPOを意味する場合、バックアップからサーバーシステムを復元する際に、ランプポートスキームには特定の問題があります。リクエストで以前に観測された値Aの値を再度送信するようにサーバーに指示します。 システムがある程度の余裕を持ってオフラインになっている間の識別。



再初期化



そしてスキームの最後の問題:認証されたカウンターAが値Nに近づいたらどうするか? この状況は再初期化と呼ばれます。 Lamportの初期バージョンでは、再初期化には認証情報の完全な再生成、つまりクライアント側のPとサーバー側のH N (P)の置換が含まれます。 ユーザーのパスワードからPを生成する場合、ハッシュ合計の下で、サーバー名に加えて、rekey_id再初期化番号を入力する必要があります:P = H(パスワード||サーバー名|| rekey_id)、サーバーに保存し、各リクエストでクライアントに通知する。 または、再初期化のたびに、ユーザーパスワードを変更し、何らかの形でパスワードの完全な非再現性を確保することは、私にとってはより難しい技術的作業のようです。 ところで、よく知られているPを使用したパスワード攻撃から保護するために、N番目の認証の前に少なくとも1ステップを再初期化して、クライアントがオープンチャネルを介してPの値を送信する必要がないようにすることは悪くありません。



過去7-8年にわたって、自己初期化ハッシュチェーンに関するいくつかの最新の作品が一度に公開されています(「再初期化可能なハッシュチェーン」、「無限ハッシュチェーン」、または「自己更新ハッシュチェーン」という用語を検索することで見つけることができます)。 しかし、ランパートのアイデアの美しさが無駄になるよりも、数学は非常に重要なものだと言いたいと思います。



最後に、認証が成功した後にのみカウンターAが(元のバージョンのように)増加し、クライアントに十分な計算能力がある場合、Nをたとえば100,000(1日あたり10認証で30年間)に設定するだけで再初期化を回避できますそれは私にとって最も合理的な解決策のようです。



全体として、Lamportのスキームは非常に実行可能であり、非対称クライアント認証の代替として実装するのがはるかに簡単です。これは、今日ではいくぶん忘れられています。



All Articles