PHP password_needs_rehash 如何判断算法参数已经过时
来源:17golang原创
时间:2026-09-14 22:01:50 139浏览 收藏
登录功能上线一段时间后,常见的一类“没有报错但安全策略没升级”问题是:数据库里的密码哈希仍然能验证成功,却已经不符合当前的算法或 cost 配置。处理这件事不能直接比较两次哈希,也不能只看到哈希字符串变长就改库。正确做法是先用 password_verify() 认证,再用 password_needs_rehash() 判断策略是否落后,只有两个判断都成立时,才用本次登录得到的明文密码生成新哈希并覆盖旧值。
官方地址:https://www.php.net/manual/en/function.password-needs-rehash.php
true表示哈希与当前算法或 options 不匹配,不表示用户密码错误。- 哈希升级必须发生在
password_verify()成功之后,函数本身不能验证 MD5 或 SHA1。 PASSWORD_DEFAULT可能随 PHP 版本变化,数据库字段应能容纳未来的完整哈希。
password_needs_rehash 比较的到底是什么
PHP 的密码哈希是自描述字符串,通常携带算法标识、算法参数和随机 salt。password_needs_rehash($hash, $algo, $options) 会拿这些信息与当前传入的算法和 options 比较;只要算法不同,或关键参数不符合,就返回 true。所以它回答的是“这条哈希要不要按当前策略重算”,不是“这次密码对不对”。
| 判断对象 | 示例 | 含义 |
|---|---|---|
| 算法 | PASSWORD_DEFAULT | 当前默认算法是否仍匹配 |
| 参数 | cost、memory_cost | 计算强度是否符合策略 |
| 返回值 | true / false | 是否需要重新生成哈希 |

例如当前策略从 bcrypt cost 12 提高到 13,旧哈希仍可能通过 password_verify(),但拿同一组新 options 判断时会得到 true。这正是渐进升级的入口:不用强迫所有用户一次性重置密码,而是在下一次成功登录时更新。
为什么必须先验证密码再重算哈希
故障复盘时最危险的改法,是拿请求参数直接调用 password_needs_rehash(),或者只要它返回 true 就把新哈希写回。该函数不检查明文密码,未验证的输入不应拥有改写用户凭据的机会。
12];
// $password 是本次登录输入,$storedHash 来自用户记录。
if (password_verify($password, $storedHash)) {
// 只有认证成功,才判断旧哈希是否落后于当前策略。
if (password_needs_rehash($storedHash, $algo, $options)) {
// 重新使用已验证的明文密码生成随机盐哈希。
$newHash = password_hash($password, $algo, $options);
// 用条件更新或事务写回,避免覆盖并发修改后的记录。
updateUserPasswordHash($userId, $newHash);
}
loginUser($userId);
}
?>
这里有两个独立的成功条件:第一个确认“人知道密码”,第二个确认“哈希策略需要升级”。如果第一个失败,流程直接结束;如果第一个成功、第二个为 false,照常登录但不写库;两个条件都满足,才进入重算和写回。

旧哈希升级时最容易漏掉的三个边界
第一,不要把 MD5、SHA1 或自定义字符串直接交给这个函数期待它“识别并修复”。这套 API 面向 password_hash() 生成的哈希;真正的遗留算法需要在兼容认证分支中单独验证,确认密码正确后再转成新格式。
第二,升级参数必须来自统一策略,而不是散落在登录控制器里的魔法数字。bcrypt 的 cost、Argon2 的 memory_cost、time_cost 和 threads 都应和实际机器负载一起评估。提高 cost 会增加登录计算时间,不应只因为数字更大就盲目修改。
第三,保存哈希时不要截断字段,也不要手工固定 salt。PHP 手册说明 PASSWORD_DEFAULT 的默认算法未来可能变化,常见的密码字段应按可变长度设计,例如使用能容纳完整哈希的 255 字节字段;更新动作还应处理并发登录,避免后写入的旧策略覆盖先写入的新策略。
常见问题
password_needs_rehash 返回 true 是密码错了吗?
不是。它只说明算法或 options 与当前策略不一致,密码是否正确必须由 password_verify() 判断。
每次登录都要重新生成密码哈希吗?
不需要。只有验证成功且 password_needs_rehash() 返回 true 时才重算,其他情况直接完成登录。
可以用 password_needs_rehash 判断 MD5 哈希吗?
不能把它当作 MD5/SHA1 识别器。遗留哈希要保留独立的兼容校验,成功后再用现代密码 API 完成迁移。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
文章 · php教程 | 16分钟前 | php教程 · session_start · PHP会话 · PHP配置排查 · 目录权限 · session.save_path PHP session_start PHP会话保存路径 session_save_path排查 PHP会话目录权限489 收藏
-
323 收藏
-
369 收藏
-
315 收藏
-
201 收藏
-
337 收藏
-
444 收藏
-
文章 · php教程 | 10小时前 | php教程 · 日期处理 · DatePeriod · 时间区间 · 参数语义 · PHP DatePeriod DatePeriod INCLUDE_END_DATE PHP 日期区间结束日期 PHP 日期周期边界 DatePeriod recurrences355 收藏
-
164 收藏
-
439 收藏
-
157 收藏
-
216 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习