PHP Conference Japan 2024

password_needs_rehash

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

password_needs_rehash检查给定的哈希值是否与给定的选项匹配

说明

password_needs_rehash(string $hash, string|int|null $algo, array $options = []): bool

此函数检查提供的哈希值是否实现了提供的算法和选项。如果不是,则假定需要重新哈希该哈希值。

参数

hash

password_hash() 创建的哈希值。

algo

一个密码算法常量,表示对密码进行哈希处理时使用的算法。

options

包含选项的关联数组。有关每个算法支持的选项的文档,请参阅密码算法常量

返回值

如果应该重新哈希该哈希值以匹配给定的 algooptions,则返回 true,否则返回 false

更新日志

版本 说明
7.4.0 现在 algo 参数需要一个 string,但为了向后兼容,仍然接受 int

示例

示例 #1 password_needs_rehash() 的用法

<?php

$password
= 'rasmuslerdorf';
$hash = '$2y$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';

$algorithm = PASSWORD_BCRYPT;
// 随着硬件的改进,bcrypt 的 cost 参数可能会随时间而改变
$options = ['cost' => 12];

// 针对明文密码验证存储的哈希值
if (password_verify($password, $hash)) {
// 检查算法或选项是否已更改
if (password_needs_rehash($hash, $algorithm, $options)) {
// 如果是,则创建新哈希值,并替换旧哈希值
$newHash = password_hash($password, $algorithm, $options);

// 使用 $newHash 更新用户记录
}

// 执行登录。
}
?>

添加注释

用户贡献的注释 3 个注释

27
php dot net at muer dot nl
10 年前
此函数无法检查字符串是否为 MD5 或 SHA1 哈希值。它只能告诉你使用 password_hash 函数哈希处理的密码是否需要再次通过哈希函数以跟上新的默认值。

只有当你的用户登录并且你已经通过 password_verify 检查输入的密码实际上是正确的时,你才能使用此函数。此时,如果 password_needs_rehash 返回 true,则可以将明文密码通过 password_hash 函数。
11
geekasylum at google mail
6 年前
此函数确实可以用于协助透明地更新旧密码(那些不使用 password_hash() 函数的密码 - 例如:可能使用 MD5 或 SHA1 的密码)

在旧网站中,当对用户进行身份验证时(在登录期间)首先使用 password_verify() 检查密码。如果失败,则可能仅仅是因为用户的密码哈希值是很久以前由旧的或自制的密码算法创建的。

然后,你可以根据网站的旧密码算法重新检查密码。如果也失败,则登录失败,因为提供的密码未通过新的或旧的密码测试进行身份验证。

如果这两个测试中的任何一个成功,则你知道密码是正确的,因此你将对存储的哈希值调用 password_needs_rehash(),它将正确指示是否需要重新计算密码哈希值,要么因为它是未识别的(旧)哈希值,要么它是 password_hash() 创建的现代哈希值,可能只需要更新其 cost 索引。

只需将重新计算的哈希值存储在数据库中,你现在就拥有了该用户的 password_verify() 兼容密码,并且可以在将来的登录中跳过第二次测试(但仍需检查是否需要重新哈希)。
13
admin at torntech dot com
10 年前
password_needs_rehash 函数的其他一些用例是当你指定使用 password_hash 的 PASSWORD_DEFAULT 算法时。
如密码哈希预定义常量和 password_hash 页面中所述,PASSWORD_DEFAULT 使用的算法可能会随着不同版本的 PHP 的发布而更改。
此外,如果你更改了 password_hash 选项的可选 cost 或静态 salt(不要使用静态 SALT)要求,则将使用 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
To Top