web-dev-qa-db-ja.com

HMAC-なぜパスワードの保存にHMACを使わないのですか?

Nota bene:パスワードストレージを保護するための 良い答えscrypt または bcrypt のいずれかであることを認識しています。この質問は、実際のソフトウェアでの実装に関するものではなく、私自身の理解によるものです。

Joe ProgrammerがWebアプリケーションのデータベースにエンドユーザーのパスワードを安全に保存するを課されているとします。または、ソフトウェアにログインするためのパスワードをディスクに保存します。彼はおそらくそうするでしょう:

  1. エンドユーザーから_$password_を取得します。
  2. _$nonce_を64ビットまたは128ビットのランダムな値として作成します。
  3. $hash = SHA256($nonce$password)を作成し、_$nonce_を_$hash_とともにデータベースに格納します。

質問1:

以下が上記よりも実質的に優れていないのはなぜですか?

  1. _$long_string_を一度だけ作成します。これを定数としてアプリケーションコードに格納します。 _$long_string_はf.x. 2キロバイトのランダムな文字。
  2. エンドユーザーから_$password_を取得します。
  3. $mac = HMAC-SHA256($long_string)[$password]を作成し(つまり、エンドユーザーのパスワードをキーとして使用してMACを作成し)、この_$mac_をデータベースに保存します。

HMACには次の利点があると思いますか?

  • 衝突はそれほど頻繁ではありませんか?
  • それは単純なハッシュよりも計算上いくらか高価です? (もちろん、scryptの近くにはありません。)
  • 適度な時間内にブルートフォース攻撃を成功させるためには、攻撃者は次の2つにアクセスする必要があります:1)データベース、ここで_$mac_は2)元の_$long_string_が格納されているアプリケーションコード。これは、攻撃者がデータベースへのアクセスのみを必要とするハッシュ関数よりも優れていますか?

しかし、それでも誰もHMACの使用を提案しているようには見えないので、私は何かを誤解しているに違いありませんか?

質問2:

ソルト値_$nonce_を追加する意味は何ですか?

  1. _$long_string_を一度だけ作成します。これを定数としてアプリケーションコードに格納します。
  2. エンドユーザーから_$password_を取得します。
  3. 約128ビットのランダムな値として_$nonce_を作成します。
  4. $mac = HMAC-SHA256($long_string)[$nonce$password]を作成し、_$nonce_および_$mac_をデータベースに格納します。
46
Jesper M

ソルトのポイントは、攻撃コストの共有を防ぐことです。攻撃者が2つのパスワードを攻撃したい場合、1つのパスワードを攻撃するよりも2倍の費用がかかるはずです。

提案(「質問1」)では、同じパスワードを持つ2人のユーザーが同じMACを使用することになります。攻撃者がデータベースへの読み取りアクセス権を持っている場合、攻撃者は(MACを再計算することによって)パスワードを「試行」し、一致するデータベースを検索できます。その後、パスワードを攻撃するコストで、allパスワードを並行して攻撃できます。もしあなたの long_stringは、アプリケーションのソースコードにハードコードされた定数であり、インストールされているアプリケーションのすべてのインスタンスがこの定数を共有します。また、「aレインボーテーブル」。

ナンス(「質問2」)を使用すると、コストの共有を回避できます。ナンスは通常「塩」として知られています。君の long_stringそして、HMACの使用はここではあまりあなたを買いません(そして、あなたはそれがそのために設計されたもののためにHMACを使用していないので、あなたは暗号的に言えば不安定な基盤にいます)。ソルトを使用することは非常に良いアイデアです(まあ、notソルトを使用することは少なくとも非常に悪いアイデアです)が、それは仕事の半分しか行いません。 slowハッシュプロシージャも必要です。ここでのポイントは、ソルトはコストの共有を防止しますが、単一のパスワードの攻撃を防止しないということです。パスワードを攻撃するということは、一致するまで可能なパスワードを試すこと(つまり、「辞書攻撃」)を意味し、平均的な人間のユーザーの想像力を考えると、辞書攻撃は機能する傾向があります。人々はlove推測される。回避策は、通常ハッシュ関数を数千回繰り返すことにより、本質的に遅いハッシュプロセスを使用することです。アイデアは、パスワード検証をより高価にすることです。ユーザーに1µsではなく1ms待機させることは難しいことではありません(ユーザーはそれに気付かないでしょう)が、辞書攻撃は1000倍も高価になります。君の long_stringmayそれが本当に長い場合に使用されます(2キロバイトではなく、20メガバイト)。

HMAC mayパスワード検証システムを強化するために生のハッシュ関数の代わりに使用されますが、設定が異なります。 saltと反復ハッシュ関数でパスワードをチェックするシステムが与えられた場合、秘密鍵[〜#〜] k [〜#〜]を使用して、ハッシュ関数をHMACに置き換えることができます。 [〜#〜] k [〜#〜]秘密にしておくことができる限り、これはオフライン辞書攻撃を防ぎます。値のシークレットを維持することは簡単ではありませんが、完全なデータベースよりも128ビット[〜#〜] k [〜#〜]シークレットを維持する方が簡単です。

35
Thomas Pornin

HMACはここではあまり購入しませんが、これは交換可能なハッシュ関数(キーを変更することで交換可能)として機能すると思います。とにかく、ここではやり過ぎのようです。

ただし、上記で提案した最初のスキームは、$ long_stringが攻撃者に知られると破滅的に失敗します。これは、おそらくコードが秘密であると見なされていないためです(そして、とにかくコードの機密性に依存することは一般的に不十分です)。

事前計算された攻撃から保護するには$ nonceが必要なので、2番目のスキームを使用する必要があります。

3
frankodwyer