PHP 密码加密方案对比:MD5、SHA、bcrypt
在用户认证系统中,**安全地存储密码**是开发者的第一道防线。错误的加密方式可能让整个应用暴露于严重风险之中。本文简明对比三种常见方案:MD5、SHA 系列与现代推荐方案 password_hash()(基于 bcrypt)。
❌ MD5:已淘汰,绝不用于密码
MD5 是哈希算法,但不是加密算法,且早已被证明存在严重碰撞漏洞。它无盐值、计算极快,极易被彩虹表或暴力破解。
// ❌ 危险示例(仅作演示,切勿使用!)
$password = "123456";
$md5_hash = md5($password); // "e10adc3949ba59abbe56e057f20f883e"
❌ SHA-1 / SHA-256:仍不适用于密码
SHA 系列虽比 MD5 更安全,但仍是快速哈希函数——攻击者可每秒尝试数亿次。若未加盐且重复使用,依然脆弱。
// ❌ 不推荐(缺乏自适应成本控制)
$sha256 = hash('sha256', '123456' . 'static_salt'); // 静态盐值易被预计算
✅ bcrypt:PHP 原生推荐方案
PHP 自 5.5+ 内置 password_hash() 和 password_verify(),默认使用 bcrypt 算法。其核心优势:
- 自动加盐(salt),每次调用生成唯一哈希
- 可调节计算成本(cost factor),抵御算力提升
- 抗 GPU/ASIC 暴力破解(设计为计算密集型)
- 验证逻辑简单安全,无需手动处理盐值
// ✅ 正确做法:一行生成,一行验证
$password = "MySecureP@ssw0rd!";
// 生成哈希(默认 cost=10,可指定如 ['cost' => 12])
$hash = password_hash($password, PASSWORD_BCRYPT);
// 示例输出:"$2y$10$9ZvzVQx...(60字符,含算法、cost、salt和哈希)"
// 验证时直接比对原文 —— 自动提取 salt 并重算
if (password_verify($password, $hash)) {
echo "登录成功!";
} else {
echo "密码错误。";
}
✅ 最佳实践提示:
• 始终使用
• 无需存储 salt —— 它已编码在哈希字符串中
• 定期升级 cost 参数(如从 10 → 12)以应对硬件进步
• PHP 8.0+ 还支持
• 始终使用
password_hash() + password_verify()• 无需存储 salt —— 它已编码在哈希字符串中
• 定期升级 cost 参数(如从 10 → 12)以应对硬件进步
• PHP 8.0+ 还支持
PASSWORD_ARGON2I/PASSWORD_ARGON2ID(需 libsodium)
⚠️ 特别注意:
•
• “加盐 MD5” 或 “SHA256 + 时间戳” 仍是伪安全,无法替代自适应哈希
• 永远不要自己实现密码哈希逻辑 —— 使用经过审计的原生函数
•
md5()、sha1()、crypt()(未配 bcrypt)等函数均不应再用于密码• “加盐 MD5” 或 “SHA256 + 时间戳” 仍是伪安全,无法替代自适应哈希
• 永远不要自己实现密码哈希逻辑 —— 使用经过审计的原生函数
总结:安全不是功能,而是持续实践。从今天起,请用 password_hash() 替代所有老旧哈希方案——这是 PHP 社区十年验证的最佳答案。