MD5和SHA1已被实战攻破且被NIST弃用,绝对不可用于密码存储;SHA256虽抗碰撞但过快、无自动加盐与耗时调控;唯一推荐方案是PHP内置的password_hash()与password_verify(),自动加盐、可控耗时、支持算法升级。

因为它们已被实战攻破,不是“不够安全”,而是根本不能用。
md5() 和 sha1() 已被 NIST 正式弃用,且存在可复现的碰撞攻击
MD5 在 2004 年就被证明存在系统性碰撞漏洞;SHA-1 的首个公开碰撞(SHAttered)由 Google 在 2017 年演示,实际攻击成本远低于理论值。PHP 8.5.7 虽未移除这两个函数,但官方文档和安全指南明确标注:它们仅适用于校验文件完整性等非安全场景,md5() 和 sha1() 绝对不可用于密码哈希。
- 调用
md5("password")永远输出固定字符串,攻击者拿到数据库后可直接查彩虹表还原弱密码 - 以
0e开头的哈希值(如md5("240610708") === "0e462097431906509019562988736854")在 PHP 弱类型比较中会被当作科学计数法解析为 0,导致绕过验证 - 二者均无盐值、无计算耗时控制,现代 GPU 每秒可暴力尝试上亿次
hash("sha256", $pwd) 也不行,哪怕你手动加盐
hash("sha256", $data) 是通用哈希接口,设计目标是快——这恰恰与密码存储需求相反。它不自动加盐,不支持 cost 参数,无法抵抗硬件升级带来的破解速度提升。
- 你得自己生成随机盐、拼接、存储、读取、再比对,极易出错(比如盐写死、没随机、长度不足)
- 即使加了盐,SHA-256 计算太快,8 位字母+数字组合平均几分钟就能被暴力穷举完
- PHP 官方文档反复强调:
hash()不适用于密码哈希
唯一合规做法:只用 password_hash() + password_verify()
PHP 5.5+ 内置的 password_hash() 是唯一推荐方案,它默认使用 PASSWORD_BCRYPT,未来可通过 PASSWORD_DEFAULT 自动升级到 Argon2。
立即学习“PHP免费学习笔记(深入)”;
- 自动处理盐值:每次调用生成全新随机盐,无需你存、取、拼接
- 可控耗时:通过
['cost' => 12]控制单次哈希约 100ms,拖慢暴力尝试节奏 - 输出自带算法标识和盐,
password_verify()可直接比对,兼容未来算法演进 - 别试图“包装”它:写成
my_hash($pwd)再调用password_hash()没意义,直接用原生函数
真正容易被忽略的是:很多老项目里 md5() 或 sha1() 看似只是“校验 token”或“生成缓存 key”,但只要输入可控(比如用户能提交任意字符串),就可能被用于构造碰撞或绕过逻辑。安全边界不在函数名,而在上下文是否允许攻击者影响输入。



















