※ PHP 5.5.0+でpassword_verify()が使えるならそれがいいよ?
crypt()
で作った2つのハッシュ化文字列を照合する方法。
なぜかどこにも書いてないので、Perlの知識を活用することになった。
プログラミングPerl 第3版 VOLUME 1
照合のためのcrypt()
照合時にソルトを作っちゃだめだよ?
// パスワードの照合
if (crypt(平文パスワード, DBにあるハッシュ化パスワード) === DBにあるハッシュ化パスワード)
ソルトだけパスワードと別に保存しておいてもいいけどね。crypt()
の戻り値にもソルトは含まれてるし、ソルトの後は使われないので、こうしたほうが簡単。
ソルトを固定値にする方法もあるね。無いね。あるかもね。やっぱり無いね。
ソルトはどのように保存すればいいのですか?
password_hash()
や crypt()
を使った場合、戻り値であるパスワードハッシュの中にソルトが含まれています。 このソルトは、そのままの形式でデータベースに格納する必要があります。 というのも、利用したハッシュ関数の情報がそこに含まれており、それを直接 password_verify()
や crypt()
に渡せばパスワードの検証ができるからです。
────なんとなく書いてあったね…。「パスワードハッシュごと格納」って書かなきゃ全然広まらないよ…。password_verify()のほうではハッシュをそのまま渡してるからね。そこでやっと「crypt()
にもハッシュをまるごと渡すのか!」って分かる仕組みだから息の長い伏線だったね。
利点
この方法のいいところは複数のアルゴリズムを併用できる点。既存のパスワードはそのままで、いつでも強力なアルゴリズムに移行できることだよね。それまでのアルゴリズムも使えなきゃいけないけど、新しいハッシュは新しいアルゴリズムで作っていい。
ソルトにはハッシュ化アルゴリズムの選択とそのパラメーターも含めてるから、いくつアルゴリズムを併用してもソルトで(crypt()
が自動的に)判断できるというわけ。この点はPHP 5.5.0以降のpassword_hash()
, password_verify()
と同じ。
パスワードを変更するたびにソルトをランダムに作っていいので、同じパスワードが同じハッシュにならないようにできるのもいいところ。
おまけ : Blowfishでパスワードをハッシュ化
† PHP でパスワードを保存するなら Blowfish でハッシュしよう | バシャログ。
function blowfish($password_raw, $cost = 7) {
$cost = max(4, min(31, $cost));
$prefix = '$2a$' . sprintf('%02d', $cost) . '$';
// '$2a$'はPHP 5.3.7未満向け。PHP 5.3.7+なら'$2y$'を使っとく。(公式ドキュメントにそう書いてあるからそうしとけ以上の意味は無い)
// 別に最新版でも'$2a$'で良さそうなんだけど、何か間違いを起こして古いPHPで動かしちゃったときにエラーになるようにするためなのかな。(だとしても方法が間違い)
// 5.3.7未満のPHPでBlowfishハッシュ化したパスワード、かつ非ASCII文字を含むなら$2x$じゃないと照合できない。トノコト ((\\( ⁰⊖⁰)/))
// † http://kanonji.info/blog/2014/07/08/crypt_blowfishのアルゴリズム2a-2x-2yについて英語のドキュメ/
// '$2x$'のxは「バッテン」という意味なのかね。
// Blowfishのソルトに使用できる文字種
$chars = array_merge(array('.', '/'), range('0', '9'), range('A', 'Z'), range('a', 'z'));
$salt = '';
for ($i = 0; $i < 22; $i++) { // 22...Blowfishに必要なソルトの長さ
$salt .= $chars[mt_rand(0, count($chars) - 1)];
}
return crypt($password_raw, $prefix . $salt);
}
あっ…この照合方法参考にした記事と同じだわぁ…。知ってる人は当たり前のようにこうしてるんだね…。