《PHP8上級試験対策》BCRYPTの72バイト制限とpassword_verifyの落とし穴

  • URLをコピーしました!

はじめに

password_hash()password_verify() を使えば、PHPで安全なパスワード認証が実現できます。
しかし、現在 PASSWORD_DEFAULT に指定されている PASSWORD_BCRYPT には「72バイト制限」という重要な仕様があります。この制限を理解していないと、「異なるパスワードが同じと判定される」という思わぬ落とし穴にハマる可能性があります。

この記事では、PHP8上級試験でも頻出の「BCRYPTの72バイト制限」とその実際の動作を、実行例と図解でわかりやすく解説します。

キーワード: password_hash / password_verify / PASSWORD_DEFAULT / PASSWORD_BCRYPT / 72バイト制限 / パスワードハッシュ

目次

🔍 実行コード

<?php
declare(strict_types=1);
error_reporting(-1);

$raw_password = str_repeat('a', 72);
var_dump($raw_password);

$hash = password_hash($raw_password, PASSWORD_DEFAULT);

$r = password_verify($raw_password, $hash);
var_dump($r);

$r = password_verify($raw_password . 'abc', $hash);
var_dump($r);

🧪 実行結果

string(72) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
bool(true)
bool(true)

🧠 解説

1️⃣ PASSWORD_DEFAULT の正体

PHP8系(〜8.2)では、PASSWORD_DEFAULTPASSWORD_BCRYPT を指しています。
つまり、このコードは実質的に:

password_hash($raw_password, PASSWORD_BCRYPT);

を呼んでいます。

2️⃣ BCRYPT の「72バイト制限」

BCRYPT では、パスワードの先頭72バイト までしか処理に使用されません。73バイト目以降は自動的に切り捨てられます。

3️⃣ そのため起こる現象

$raw_password がちょうど72バイトのとき、$raw_password . 'abc' を渡しても 'abc' の部分(73〜75バイト目)は無視されるため、実際には 同じ72バイトのデータを比較している ことになります。

🧩 ASCII図解で理解

入力パスワード:
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabc"
 │<------------------ BCRYPTが使うのはここまで(72バイト) --------------------->│
 │                                                                         │
 └─────────────────────────────┬───────────────────────────────────────────┘
                               │
                               ▼
               BCRYPTはここまでしかハッシュ化に使わない!

4️⃣ 結果の意味

実行内容結果理由
password_verify($raw_password, $hash)true同じ72バイトで一致
password_verify($raw_password . 'abc', $hash)true73バイト以降が無視され、一致してしまう

5️⃣ 試験での正答

この問題に対する模範解答は:

✅ この結果は「正しい(仕様通りの動作)」である。

です。
BCRYPT が72バイト以降を無視するため、仕様上は bool(true), bool(true) が正しい結果となります。

⚠️ 実務上の注意点

この仕様を知らずに運用すると、以下のような危険があります:

「72文字目以降が違うだけの異なるパスワードが、同じものとして認証されてしまう」

そのため、実務では次のような対策が推奨されます。

✅ 対策例1:パスワード長を制限する

if (strlen($raw_password) > 72) {
    throw new Exception('パスワードは72バイト以内で入力してください。');
}

✅ 対策例2:ハッシュ前に短縮(プリハッシュ)

$hashed = password_hash(hash('sha256', $raw_password, true), PASSWORD_DEFAULT);

→ これにより、どんなに長いパスワードでも 32バイトに収まります。

まとめ

項目内容
PASSWORD_DEFAULTPHP8ではPASSWORD_BCRYPT
制限72バイト以降は無視される
実行結果bool(true), bool(true) は仕様通り「正しい」
注意点長いパスワードは切り捨てられるため、制限または前処理が必要

✅ まとめコメント

password_verify() の結果が「true,true」になるのは間違いではなく、BCRYPT の仕様通りの動作です。
ただし実務では、72バイトを超えるパスワードの扱いに十分注意しましょう。

この記事が気に入ったら
いいねしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次