パスワードのハッシュ化

(更新日: 2017/03/02)

HMACを使った鍵の生成(導出)方法を書いているので、念の為にパスワードのハッシュ化方法について書いておきます。ユーザー入力のパスワードをアプリケーションデータベース等に保存する場合、HMACやHKDFを使わずに、password_hash()を使うべきです。

 

password_hashとは

パスワードをアプリケーションに保存する場合、パスワードが管理者や開発者、攻撃者によって解析/窃取されるリスクを考慮する必要があります。平文のテキストでパスワードを保存した場合、簡単に盗まれてしまいます。

password_hash関数はcrypt関数のラッパー関数です。password_hash関数でできることはcrypt関数できます。password_hash関数が存在する理由は、crypt関数の仕様が使い易いとは言えず、間違った使い方をすると安全ではないからです。

crypt関数を使った場合、ハッシュ化を行う場合の動作を$saltに”テキスト”として指定しなければなりません。crypt関数を安全に利用するには、利用するハッシュ、ハッシュ関数の適用回数などを$saltの値に設定する必要があります。

以下はpassword_hash関数の実行例です。

  • “$2y$”がハッシュ関数の指定(この場合、Blowfish)
  • “$10$”の10がハッシュ関数の実行回数の指定(この場合、Blowfishなので2^10 = 1024回)
  • “XjfAtRDfO32a2JaSwcCvZeS.NZLn5H8FloFhGlcFm7XN44pj15.Jm”が自動的に付与されたsaltとsaltとパスワードから計算したハッシュ値

使用したハッシュ関数、適用回数、saltもハッシュ値もすべて記述されています。ブルートフォース攻撃を行う為に十分な条件ですが、password_hash(crypt)は多量のCPU計算量を必要とさせることによりブルートフォース攻撃を”緩和”しています。

緩和しているだけで、上記の実行例のような”password”といった、使ってはならない単純なパスワードの場合は簡単に解析できます。 何千、何万ユーザーのパスワードを解析するには膨大すぎる時間が必要ですが、特定ユーザーのパスワード解析なら十分に可能です。

 

 

パスワードなので、ユーザーが入力した文字列とシステムが保存している文字列(データ)が一致しているか確認する必要があります。何らかの方法で照合できるようにしなければなりません。このためpassword_hash関数(crypt関数)はユーザーが入力したパスワードをできるだけ安全な形でハッシュ化します。

  • 暗号学的なハッシュ関数を使う(現在のデフォルトはBlowfish)
  • 暗号学的に安全なsaltを自動設定する(CSPRNGからsalt値を取得する)
  • ハッシュ関数に対して適当な適用回数(rounds)を自動的に設定する(ブルートフォース対策)
  • 自動的に利用しているハッシュ関数を検出する(password_verify

password_hash関数は$algoで指定されたアルゴリズムを使い、適当なroundsでパスワードをハッシュ化します。rounds(cost)は$optionsで変更できます。

password_hash関数は暗号学的なハッシュ関数で複数回ハッシュ化を行い、攻撃者がパスワードのハッシュ化文字列を取得した場合でも、パスワード解析に多くのコスト(CPU時間)が必要となるようになっています。

  • crypt()はSHA256やSHA512をサポートしているが、password_hash()はBlowfishしかサポートしていない。これはSHA256/512に比べ、Blowfishハッシュの計算には多くのCPUが必要であることが理由です。
  • Blowfish(PASSWORD_BCRYPT)のデフォルトのrounds(cost)は10、つまり2^10回ハッシュ化を行う。

roundsは比較的少な目に設定されています。計算量が多過ぎるとDoS攻撃の原因になるからです。小型PC(IoT)などでは10(2^10)のrounds(cost)でも結構厳しいでしょう。現在の高速なCPUを対象にするなら11〜14程度にする方が良いと思います。アプリケーションの重要性に応じて設定すると良いでしょう。

password_hash関数では利用できませんが、crypt関数でSHA256を使う場合、少なくとも1万回以上のroundsを設定する方が良い1です。Blowfish(BCRYPT)とSHA256/512ではrounds(cost)の設定が2のべき乗と実際の処理回数と異なっている点に注意してください。詳しくはcrypt関数のマニュアルを参照してください。

 

HMACの安全性

ユーザーが入力したパスワードを直接暗号鍵に利用するのは好ましくありません。ユーザー入力のパスワードは極端に弱い鍵になるからです。HMAC(hash_hmac関数)を使って安全な鍵を導出可能ですが、password_hash関数とは前提条件が異なります。

password_hash関数

  • 目的:ハッシュ関数もsalt(第二の鍵)もハッシュ値も分かっているが、鍵(パスワード)の解析を困難にさせる。
  • 安全性:大量のCPU計算量でブルートフォース攻撃を緩和する。簡単な鍵(パスワード)なら簡単に解析できる。

hash_hmac関数

  • 目的:暗号学的なハッシュ関数に多少の問題があっても、暗号学的に安全なハッシュ値を生成する。
  • 安全性:安全性は入力データ(このエントリの場合パスワード)かsalt(第二の鍵)のどちらかが暗号学的に安全かつ秘密であることが条件。入力データが弱いパスワードでも強い秘密のsalt(第二の鍵)により、出力されたハッシュ値の安全性は暗号学的に保証される。

 

まとめ

password_hash関数とhash_hmac関数は作られた目的も、それなりに安全に動作する条件も異ります。

このエントリでは一つ一つの基礎的な概念や仕様を丁寧に説明していないです。理解り易く説明できていないですが、利用目的に合わせて適切な関数を利用しましょう。

hash_hmac関数を利用する場合でも、”何かの目的、例えば暗号化、の為にユーザー入力のパスワード”をデータベースに保存する必要があると思います。その場合、hash_password関数を使うとより安全です。

参考:password_hashの重要な制限


  1. パスワード管理ツールなどではCPU計算量を増やすためにSHA2ハッシュ関数を10万回単位で繰り返し適用しています。 

Comments

comments