web-dev-qa-db-ja.com

キー付きパスワードハッシュを実装する正しい方法は何ですか?

この素晴らしい リンク で述べたように、与えられたパスワードを与えられたユーザーのPBKDF2ハッシュを取得する方法

  1. パスワード(もちろん)、
  2. 塩(暗号的に安全な乱数ジェネレーターで生成されます。
  3. 反復回数(アプリケーションのユーザビリティ許容度のバランスを取りながら安全を確保するのに十分な数を選択)
  4. ハッシュサイズ(計算されるハッシュの長さ)

/** * Computes the PBKDF2 hash of a password. * * @param password the password to hash. * @param salt the salt * @param iterations the iteration count (slowness factor) * @param bytes the length of the hash to compute in bytes * @return the PBDKF2 hash of the password */ private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8); SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM); return skf.generateSecret(spec).getEncoded(); }今私の質問は:

パスワードのキー付きハッシュはどのように実装する必要がありますか?

私の読書に基づいて、これは私の考え方です。検証してください。

  • メソッドpbkdf2(上記のコードスニペット内)のsalt引数を秘密にしておきます(安全性の高いHSMから取得します)。 必要に応じてパスワードハッシュと一緒にデータベースに保存するのとは対照的です)。

  • ソルトはランダムであることが意図されているため(レインボーテーブル/辞書攻撃からそれらを保護するため)、pbkdf2に提供されるソルトは、キーとCSPRNGから生成されたランダムバイトの連結である必要があります。

    [塩] = [秘密鍵] + [CSPRNGからのランダムバイト]

最後に、あえてばかげた質問をします(アプリケーションのユースケースの90%を認証する必要があるため、反復回数が多いとユーザビリティに深刻な問題が発生するため、あえて質問します)

反復回数を減らすことはできますかORキー付きハッシュによってセキュリティの層を追加したので、それなしで実行できますか?

P.S:ブルートフォース攻撃によってパスワードが危険にさらされる可能性を減らすことにより、低速ハッシュアルゴリズムが追加する価値を認識しています。非秘密のソルトを使用したSlowHashingアルゴリズムを備えたKeyedHashingVSによるセキュリティの付加価値について専門家にコメントしてもらいたいだけです。

1
acthota

パスワードハッシュを秘密鍵と組み合わせる1つの方法は、デバイス自体だけが知っている鍵を使用して、認証サーバーから送信されたパスワードハッシュを暗号化する別のデバイス(HSMなど)を用意することです。

ユーザーのログイン時に、認証サーバーは適切なコスト設定(サーバー/状況で許容できるもの、5ミリ秒、20ミリ秒、100ミリ秒)で低速ハッシュ(たとえばbcrypt)を計算し、結果のハッシュを暗号化デバイスに渡します。認証サーバーで確認できる暗号化されたblobを返します(authサーバーはハッシュ識別子、コスト、ソルト、可能な「暗号化デバイスキー識別子マテリアル」および暗号化されたblobを格納します)。

「暗号化デバイス」は、認証サーバーがハッシュを復号化することを許可せず、暗号化して暗号化されたBLOBを認証サーバーに返すだけです。

個別のキーは、認証サーバー/ハッシュデータベースと同じスレッドモデルの下にない場合、セキュリティの別のレイヤーを追加します。

強力なキーを保持する別の狭いアクセスデバイスを使用すると、リークされたユーザーデータベース(および認証サーバーファイル)を取得する攻撃を打ち負かすことができます。

1
timoh