本文目录导读:

在PHP项目中存储密码,强烈推荐使用PHP原生的 password_hash() 和 password_verify() 函数,它们内部使用的是 bcrypt 算法(默认),并且自动处理了盐(salt)和哈希的计算。
核心推荐:password_hash() 与 password_verify()
这是目前最安全、最不易出错的做法,也是PHP官方推荐的唯一标准做法。
为什么用它?
- 自动加盐:系统会为每个密码生成随机的强盐(salt),防止彩虹表攻击。
- 自动调整成本:你可以调整算法的计算复杂度(
cost),以应对未来硬件性能的提升。 - 防时序攻击:内部的哈希比较函数(
hash_equals)被设计为恒定时间执行,可防止时序侧信道攻击。 - 向前兼容:如果未来PHP版本改变了算法,老密码依然能验证成功。
代码示例(注册时):
<?php // 用户提交的明文密码 $plainPassword = $_POST['password']; // 生成安全的哈希(自动加盐,自动选择算法) $hashedPassword = password_hash($plainPassword, PASSWORD_DEFAULT); // 将 $hashedPassword 存入数据库 // ... 你的数据库插入代码 ?>
代码示例(登录验证时):
<?php
// 从数据库取出的哈希值
$storedHash = '从数据库查询出来的哈希';
// 用户输入的密码
$inputPassword = $_POST['password'];
// 验证密码是否正确(内部使用了安全比较)
if (password_verify($inputPassword, $storedHash)) {
echo "登录成功";
} else {
echo "密码错误";
}
?>
了解底层算法(根据需求选择)
PHP 支持以下几种算法,你可以作为 password_hash() 的第二个参数传入:
| 算法常量 | 描述 | 是否推荐 |
|---|---|---|
PASSWORD_DEFAULT |
默认算法(目前是 PASSWORD_BCRYPT)。推荐 |
⭐⭐⭐⭐⭐ |
PASSWORD_BCRYPT |
bcrypt 算法,自带盐,输出长度60字符。 | ⭐⭐⭐⭐⭐ |
PASSWORD_ARGON2I |
Argon2i 算法,基于内存的哈希,抗GPU攻击更强(PHP 7.2+)。 | ⭐⭐⭐⭐(若环境支持) |
PASSWORD_ARGON2ID |
Argon2id 算法,综合了 Argon2i 和 Argon2d 的优点(PHP 7.3+)。 | ⭐⭐⭐⭐⭐(若环境支持) |
性能与安全调整(推荐在注册时增加cost):
<?php
// 调整 bcrypt 的计算成本(默认是10,推荐12)
$options = [
'cost' => 12, // 数值越高,计算越慢,越安全
];
$hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT, $options);
?>
绝不推荐的做法(警告!)
- 不使用
md5()或sha1():这些都是快速哈希算法,GPU可以每秒算几十亿次,破解极快,除非你只是做校验和(非敏感数据),否则绝对禁止用于密码。 - 不使用
sha256()/sha512():虽然比MD5强,但依然太快,不适合单独用于密码存储,别被一些老教程误导。 - 不自己写加密逻辑:自己写的加盐/哈希组合很容易有漏洞(如盐太弱、哈希拼接方式错误)。
- 不使用可逆加密:如
base64、AES,密码一旦被脱库,攻击者可以直接解密回明文。 - 不使用双向加密:永远不要尝试解密密码,用户忘记密码只能重置,而不是告诉你旧密码。
完整的安全建议(补充)
- 密码重置时不发送明文:永远不要通过邮件发送明文密码,发送一次性重置链接即可。
- 使用 HTTPS:确保密码在传输过程中是加密的。
- 数据库泄露场景下的考虑:即使数据被脱库,由于你的哈希算法足够强(且盐随机),攻击者短时间内(甚至几年内)无法通过暴力破解得到密码。
- 保持PHP版本更新:PHP团队会持续优化加密相关函数的安全性和性能。
一句话结论: 直接使用 password_hash()(默认算法)与 password_verify() 就足够了,如果你需要极致安全且环境支持,可以选用 PASSWORD_ARGON2ID 并提供额外的内存参数。
这种方案已足够防御大多数Web攻击,并且是OWASP(开放Web应用安全项目)推荐的标准做法。