gallu’s blog

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

password_hashをどうやって使おうか?(04/15修正)

なんか最近「パスワード、いくつかの単語を組み合わせた長い文字列のほうが安全だよねぇ」的なお話が云々。
それを考えた時、今まで割と気にならなかった「警告 PASSWORD_BCRYPT をアルゴリズムに指定すると、 password が最大 72 文字までに切り詰められます。」が、途端に気になりだしてきたり。


ふと考える2つのコード、果たしてどっちがベターなのだろう?
或いは、変わらんかなぁ?
一応おいちゃんの中にはイメージがあるんだけど、ふと、問いかけてみたいように思ったので、書いてみる。

どうも、どっちも危ないっぽい。後述を参照のこと。


コード1(アウト)

$pass = パスワード;
if (72 < strlen($pass)) {
    $pass = hash('sha512', $pass, true);
}
$h = password_hash($pass, PASSWORD_DEFAULT, ['cost' => 10]);


コード2(アウト)

$h = password_hash(hash('sha512', $pass, true), PASSWORD_DEFAULT, ['cost' => 10]);


costの明示指定は趣味だ気にスンナw*1


さて。コード1とコード2、どっちがどうなんだろう???


追記
徳丸さんがfacebookで書かれていたんだけど。
「password_hash 関数はバイナリセーフでない」んだそうだ……………え?まぢで?
徳丸さんが載せていた、検証コード。

$password = "LmUb9dTqXUTTCuCxzCct3n2lIf/zS3IeZ15mtCivl0TQlD97YZtxK+u0j4AploaErAu9uYBBfqNs4R2nQITnyq+nuLZd";
$crack = "ma";
// Use sha512's raw(binary) output
$h = password_hash(hash('sha512', $password, true), PASSWORD_DEFAULT);

// Verify
$r = password_verify(hash('sha512', $crack, true), $h);

var_dump($r); // TRUEが返る

うん通った orz
コード1なら「上述は防げる」けど、「72文字を超える文字列同士で「任意箇所に\0が入ってくる」なら突破できるから、あんまりよろしくないぽげ。


さて思案。
「バイナリが駄目なら、base64にすればいいぢゃない」とか思うんだけど、sha512はbase64にしても88バイト使うから駄目なんだよねぇ。
ってなわけで、おとなしく素直に「16進数表記のsha256」が落としどころかなぁ、と。とりあえずは。


改めてコード1

$pass = パスワード;
if (72 < strlen($pass)) {
    $pass = hash('sha256', $pass);
}
$h = password_hash($pass, PASSWORD_DEFAULT, ['cost' => 10]);


改めてコード2

$h = password_hash(hash('sha256', $pass), PASSWORD_DEFAULT, ['cost' => 10]);


このどっちか、になるんかなぁ今の所だと。

*1:いや実際のところ、12くらいを指定する事が多くなってきたしねぇ