元ネタ
72文字を超えるパスワードを許容したい場合、password-hashを使うべきではない? - stack overflow
password_hash()の重要な制限
PHPマニュアル
PASSWORD_BCRYPT をアルゴリズムに指定すると、 password が最大 72 文字までに切り詰められます。
ほんとぉ?
試してみた
# php -v
PHP 7.2.7 (cli) (built: Jun 20 2018 08:21:26) ( NTS )
<?php
$pass72 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst";
//strlen($pass72) => 72
$pass73 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu";
//strlen($pass73) => 73
$hash73 = password_hash($pass73,PASSWORD_DEFAULT);
password_verify($pass72,$hash73);
// bool(true) <- !!!
というように、73 文字のパスワードのハッシュと 72 文字のパスワードが同じものとみなされてしまいました。
これはPASSWORD_DEFAULT
の値がPASSWORD_BCRYPT
、つまりCRYPT_BLOWFISH
を使っているから(?)起こるらしいです。
少なくともPHP7.1以下ではBCRYPT
以外使えないので、必ず起こります。(PHP7.2からは標準でArgon2i
が使える。)
実用上問題なさそう
ところで、上のコードは
password_verify($pass73,$hash73);
// bool(true) <- !!!
でもあります。つまりpassword_verify()
でも同様に切り詰められてから比較されるので、ユーザが72文字以上のパスワードを入力しても実用上問題はなさそうです。(ただし、90文字のパスワードを入力しても、72文字目までが同じ別のパスワードでクラックできる。)
下手にハッシュをはさんだりすると脆弱性の原因にもなりかねないので、とりあえずは72文字制限を受け入れておきましょう。どうしても気持ち悪いときはPHP7.2からpassword_hash
の第二引数にPASSWORD_ARGON2I
が使えるようになっているので、そっちを使いましょう。
おわりに
今まで何も気にせず問題なく使ってきたのですが、知ってしまうと気持ち悪い挙動なので、今後は状況を見つつPASSWORD_ARGON2I
を使っていきたい感じ