ソルトもストレッチングも両方必要

ある条件のもとでパスワードを守るには、ソルトもストレッチングも両方必要です.本当は怖いパスワードの話 (1/4):ハッシュとソルト、ストレッチングを正しく理解する - @IT がその理由の良い解説になっているのですが,4 ページに分かれていて長いので Q&A 形式でまとめてみました.
ここからの話の前提として,システムに侵入され root 権限を取られたときのことを考えています.

ソルトとストレッチングが必要な理由

Q. パスワードを暗号化でなくハッシュで保存するのはなぜか?

A. 暗号化されたパスワードは復号鍵で容易に復元できるから

パスワードを暗号化しただけでは,「root 権限の奪取」即「パスワードの流出」となってしまいます.技術的な注意を怠っていたとか過失があるとか非難されても仕方がないレベルです.

Q. 単純なハッシュではなくソルトやストレッチングを使うのはなぜか?

A. ユーザが「弱い」パスワードを使うから

ユーザが「強い」パスワード,たとえば,128 文字以上の大文字小文字数字記号が適度に混ざった無意味な文字列を確実に使ってくれるのであれば,実はソルトもストレッチングも不要です.一方,ユーザが弱いパスワードを使っている場合,パスワードをハッシュで保存しても「レインボーテーブル」や「総当たり」などの攻撃で元のパスワードを復元できてしまいます.

Q. ソルトは何のために使うのか?

A. 弱いパスワードを強くするため.

いくらパスワードをハッシュしても,パスワードが短かければ「レインボーテーブル」などを使って容易に復元できてしまいます.また,いくらパスワードが長くても辞書に載っているような単語を使っていると「辞書攻撃」で容易に復元できてしまします.このような「弱い」パスワードにソルトを連結してからハッシュすることで,「強い」パスワードと同等の強度を得ます.

Q. ストレッチングは何のために使うのか?

A. 総当たり攻撃に耐える時間を稼ぐため

いくら強いパスワードを使っても,総当たり攻撃でいつかはパスワードを復元されてしまいます.最近の CPU/GPU 性能向上により,総当たり攻撃は現実的な時間で完了する可能性があります.高速に計算できるハッシュ関数を使っていると総当たり攻撃にかかる時間が短かくなるので,計算に時間のかかるハッシュ関数を使って攻撃者に嫌がらせをしようというのがストレッチングの考え方です.うまくいくと,パスワードが復元される前に攻撃者の寿命が尽きます.すなわち,総当たり攻撃が現実的な時間で実行できなくなるということです.

おわりに

この話をまとめると,

  • root 権限取られたときに
  • 暗号化だとパスワードが流出するからハッシュする.
  • ユーザが「弱い」パスワードを使うから
    • ソルトを使って「強く」して
    • ストレッチングで総当たり攻撃に耐える時間を稼ぐ

となります.元記事の,

攻撃者によってすべての情報が盗まれるという前提に立つと、パスワードを安全に守る現状のベストプラクティスは「ソルト+ハッシュ+ストレッチング」です。

本当は怖いパスワードの話 (3/4):ハッシュとソルト、ストレッチングを正しく理解する - @IT

はその通りだと思います.

これを聞いてもソルト+ストレッチングを採用できない人は,きっと,パスワードを安全に守れない人なので別のベストプラクティスを採用しましょう.すなわち「パスワードを保存するのをあきらめて,OAuth などで外部の ID サービスを利用する」です.

Missing Parts

元記事では,

  • ソルトの長さはどれくらいが適当か
  • ストレッチングの回数はどれくらいが適当か(あるいは,key derivation 関数の構成法)

は触れられていません(例はある).これらについて,全ての環境で「これでいい」という数値はなく,状況に合わせて総合的に必要があると考えているからだと推測します.もちろん,基準とか考え方とかを提示することはできるのでしょうが,そこはきっとコンサルタントの飯の種なんだといます.