此函数无法检查字符串是否为 MD5 或 SHA1 哈希。它只能告诉您,使用 password_hash 函数哈希的密码是否需要再次通过哈希函数,以跟上新的默认值。
您唯一可以使用此函数的时间是在用户登录时,并且您已经通过 password_verify 检查了输入的密码是否正确。此时,如果 password_needs_rehash 返回 true,则可以将纯文本密码通过 password_hash 函数。
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
password_needs_rehash — 检查给定哈希是否与给定选项匹配
此函数检查提供的哈希是否实现了提供的算法和选项。如果不是,则假定哈希需要重新哈希。
hash
由 password_hash() 创建的哈希。
algo
一个 密码算法常量,用于表示对密码进行哈希时要使用的算法。
options
一个包含选项的关联数组。有关每个算法支持的选项的文档,请参见 密码算法常量。
示例 #1 使用 password_needs_rehash()
<?php
$password = 'rasmuslerdorf';
$hash = '$2y$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';
$algorithm = PASSWORD_BCRYPT;
// bcrypt 的成本参数可以随着时间的推移而更改,因为硬件有所改进
$options = ['cost' => 12];
// 验证存储的哈希是否与纯文本密码匹配
if (password_verify($password, $hash)) {
// 检查算法或选项是否已更改
if (password_needs_rehash($hash, $algorithm, $options)) {
// 如果是,则创建一个新的哈希,并替换旧的哈希
$newHash = password_hash($password, $algorithm, $options);
// 使用 $newHash 更新用户记录
}
// 执行登录。
}
?>
此函数无法检查字符串是否为 MD5 或 SHA1 哈希。它只能告诉您,使用 password_hash 函数哈希的密码是否需要再次通过哈希函数,以跟上新的默认值。
您唯一可以使用此函数的时间是在用户登录时,并且您已经通过 password_verify 检查了输入的密码是否正确。此时,如果 password_needs_rehash 返回 true,则可以将纯文本密码通过 password_hash 函数。
此函数确实可以用来帮助透明地更新旧密码(那些不使用 password_hash() 函数的密码 - 例如:可能是使用 MD5 或 SHA1 的东西)
在旧站点中,在对用户进行身份验证(登录期间)时,首先使用 password_verify() 检查密码。如果失败,则可能仅仅是因为用户的密码哈希是在很久以前由旧的或自制的密码算法创建的。
然后,您可以使用站点的旧密码算法重新检查密码。如果这也失败了,则登录失败,因为提供的密码既没有通过新的密码测试,也没有通过旧的密码测试。
如果这两个测试中的任何一个成功,则您知道密码是好的,因此您将对存储的哈希调用 password_needs_rehash(),它将正确地指示密码哈希是否需要重新计算,无论是因为它是一个无法识别的(旧的)哈希,还是因为它是由 password_hash() 创建的现代哈希,它可能只需要更新其成本索引。
只需将重新计算的哈希存储在数据库中,您现在就有了与 password_verify() 兼容的密码,并且可以在将来的登录中跳过第二个测试(但仍然检查它是否需要重新哈希)。
password_needs_rehash 函数的其他一些用例是在您指定使用 PASSWORD_DEFAULT 算法进行 password_hash 时。
如密码哈希预定义常量和 password_hash 页面所述,PASSWORD_DEFAULT 使用的算法会随着 PHP 的不同版本而改变。
此外,如果您更改了 password_hash 选项的可选成本或静态盐(不要使用静态盐)要求,则将使用 password_needs_rehash。
完整示例
<?php
$new = [
'options' => ['cost' => 11],
'algo' => PASSWORD_DEFAULT,
'hash' => null
];
$password = 'rasmuslerdorf';
// 存储的密码哈希
$oldHash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
// 验证存储的哈希是否与纯文本密码匹配
if (true === password_verify($password, $oldHash)) {
// 验证旧密码到新的 password_hash 选项
if (true === password_needs_rehash($oldHash, $new['algo'], $new['options'])) {
// 使用新的哈希重新哈希/存储纯文本密码
$newHash = password_hash($password, $new['algo'], $new['options']);
echo $newHash;
}
}
?>
上面的示例将输出类似于以下内容
$2y$11$Wu5rN3u38.g/XWdUeA6Wj.PD.F0fLXXmZrMNFyzzg2UxkVmxlk41W
即使密码强度很高,也需要重新哈希。例如
<?php
$a = '123';
$hash = password_hash($a, PASSWORD_BCRYPT, ['cost'=>16]);
var_export(password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost'=>15])); //True