パスワードのハッシュ化は比較的知られる技法となってきましたが、それと比べればソルトはまだまだ知名度が低い気がします。
単純なハッシュ化の問題点
パスワードをそのまま保管したり、復号可能な暗号化を行うような形ではもとのパスワードが判明してしまいます。そして、パスワードは正しいかどうかさえ判別できればよく、もとの値を記録しておく必要は必ずしもない1ものです。
ということで、「一方向性ハッシュ関数」という、「出力から入力の値を判別することができない」関数を使うことで、
- パスワード設定時→元のパスワードをハッシュ関数にかけて、それを記録
- ログイン時→入力されたパスワードをハッシュ関数に通して、保存されたパスワードと比較
という手順を取ることで、DBのデータから元のパスワードを簡単には復元できなくなります。
…が、ハッシュ関数を同じように通していることで、「同じパスワードが同じハッシュ値になる」という問題があります。そのため、
- 同じパスワードを使ったユーザーが一目瞭然となります。
- 事前に計算してテーブルを用意しておく2
などの攻撃が成立します。
ソルトとは
もちろん、ハッシュ関数は決定的(同じ値には同じ結果)なものなのですが、そのまま使えば上のような事態を招いてしまいます。ということで、登場するものがソルトで、
- ハッシュ化の際に、ランダムにソルトを生成して、「ソルト+パスワード」をハッシュ化する
- ソルトとハッシュ値をセットで保存しておく
- 検証のときは、「保存してあったソルト+入力すたパスワード」をハッシュ化して比較する
というような過程で使われます。ソルトとハッシュ値は一般にセットで保管されますので、「1つのパスワード」に対する攻撃に対しては特に強度が上がるわけでもありませんが、パスワードが大量に並んでいる場面でもテーブル化などの技が通用しなくなって、1つ1つ攻略する手間が生じることとなります。
便利な関数
PHPでは、その名もズバリpassword_hash()
という標準関数があります(リファレンス)。保存する値として「ハッシュ値」「ソルト」以外に「ハッシュ化アルゴリズム」も記録されますので、password_verify
で検証する際にも適切なハッシュ化アルゴリズムが自動で選ばれます。他言語でも、同様な形式でハッシュ化を行う関数があるようです。