本文目录导读:

- 推荐方法:使用
password_hash()和password_verify() - 更安全的选择:Argon2i / Argon2id
- 需要重新计算哈希吗?(密码时效检查)
- ⚠️ 常见错误(不要这样做)
- 数据库字段设计
- 扩展:盐值(Salt)
在PHP项目中,密码加密存储的最佳实践是使用密码哈希函数,而不是简单的加密或摘要算法。
核心原则:永远不要明文存储密码,也不要使用MD5、SHA1等简单哈希。
下面是推荐的几种安全且标准的密码加密存储方法:
推荐方法:使用 password_hash() 和 password_verify()
这是PHP官方推荐的最安全、最简便的方法,从PHP 5.5.0版本开始内置支持。
注册/修改密码时:
<?php // 用户提交的明文密码 $plainPassword = $_POST['password']; // 使用 password_hash() 进行哈希 // 参数1:明文密码 // 参数2:加密算法(推荐 PASSWORD_BCRYPT 或 PASSWORD_ARGON2I/ID) // 参数3(可选):选项数组 $hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT); // 或者使用更安全的 Argon2i (PHP >= 7.2) // $hashedPassword = password_hash($plainPassword, PASSWORD_ARGON2I); // 将 $hashedPassword 存入数据库(字段建议 varchar(255)) echo $hashedPassword; // 类似于: $2y$10$..... ?>
登录验证时:
<?php
// 用户输入的密码
$inputPassword = $_POST['password'];
// 从数据库读取的密码哈希值
$storedHash = '从数据库获取的哈希值字符串';
// 使用 password_verify() 验证
if (password_verify($inputPassword, $storedHash)) {
echo "密码正确,登录成功!";
// 开始用户会话
} else {
echo "密码错误!";
}
?>
优点:
- 自动生成强随机盐值(Salt)。
- 可以根据硬件性能调整算法成本(Cost Factor),这是通过
cost参数(对Bcrypt)或memory_cost、time_cost等(对Argon2)实现的。 - 算法可以升级,无需修改现有密码。
更安全的选择:Argon2i / Argon2id
如果你的PHP版本 >= 7.2,可以使用Argon2i或Argon2id算法,它比Bcrypt更抗GPU和ASIC攻击。
<?php
// 使用 Argon2id(推荐,抵抗侧信道和GPU攻击)
$options = [
'memory_cost' => 1 << 17, // 128MB内存(可根据服务器调整)
'time_cost' => 4, // 4次迭代
'threads' => 2 // 并线程数
];
$hashedPassword = password_hash($plainPassword, PASSWORD_ARGON2ID, $options);
?>
需要重新计算哈希吗?(密码时效检查)
当服务器升级或调整了算法成本(如cost从10提高到12),可以用以下方法安全地更新哈希:
<?php
// 登录成功后
if (password_verify($inputPassword, $storedHash)) {
// 检查是否需要重新哈希(算法或成本变化)
if (password_needs_rehash($storedHash, PASSWORD_BCRYPT, ['cost' => 12])) {
// 重新计算哈希并更新数据库
$newHash = password_hash($inputPassword, PASSWORD_BCRYPT, ['cost' => 12]);
// UPDATE users SET password = '$newHash' WHERE id = ...
}
// 登录成功...
}
?>
⚠️ 常见错误(不要这样做)
| 错误做法 | 原因 |
|---|---|
md5($password) |
极不安全,1秒可计算数十亿次,且无盐值 |
sha1($password) |
同样不安全 |
| 自行拼接盐值 | 容易设计出错,且无法自动升级算法 |
双向加密(AES、base64) |
密码不需要解密,只需要验证 |
| 把密码存在Cookie/URL中 | 明文暴露风险 |
数据库字段设计
存储哈希值的字段建议:
ALTER TABLE users MODIFY COLUMN password VARCHAR(255) NOT NULL; -- 或使用 TEXT 类型
- Bcrypt哈希一般60字符长。
- Argon2哈希可能更长(90-128字符),所以用255安全。
扩展:盐值(Salt)
使用password_hash()时,盐值是自动生成的,并包含在哈希结果中,你不需要自行存储盐值——它已经是哈希字符串的一部分。
例如哈希值:
$2y$10$abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ
$2y$= 算法标识10= 成本因子 (2^10次迭代)- 后面22字符 = 盐值
- 剩余部分 = 真正的哈希
最佳实践代码(完整示例):
<?php
// 注册
$hash = password_hash($password, PASSWORD_ARGON2ID, [
'memory_cost' => 65536,
'time_cost' => 4,
'threads' => 3
]);
// 登录验证
if (password_verify($inputPassword, $hashFromDb)) {
// 成功
}
?>
无特殊需求的话,直接用password_hash($password, PASSWORD_DEFAULT)即可(PHP会自动选择当时最安全的默认算法,目前是Bcrypt)。