PHP密码加密存储
PHP密码加密存储
引言
用户密码绝不能明文入库,泄露即灾难。MD5、SHA1是哈希算法但速度快、可被彩虹表破解,不适合存密码。PHP 5.5以后内置password_hash和password_verify,用bcrypt自带盐值和成本因子,是现在注册登录系统的标准做法。
注册:生成哈希入库
$pwd = $_POST['password'];
$hash = password_hash($pwd, PASSWORD_DEFAULT);
// $2y$10$.... 直接把这串哈希存数据库
$db->insert('users', ['password' => $hash]);
PASSWORD_DEFAULT默认bcrypt,自动生成随机盐,算法和成本因子都记录在哈希串里,不需要单独存盐字段。
登录:校验密码
$row = $db->find('users', ['username' => $username]);
if ($row && password_verify($inputPwd, $row['password'])) {
// 密码正确,登录成功
} else {
// 用户名或密码错误
}
password_verify自动识别哈希里的算法和盐,比对用户输入的明文,返回布尔值。
指定成本因子
$hash = password_hash($pwd, PASSWORD_BCRYPT, ['cost' => 12]);
cost越高计算越慢、抗暴力破解越强,默认10。服务器性能允许可适当调高,太慢会影响登录接口响应。
判断哈希是否需要升级
if (password_needs_rehash($row['password'], PASSWORD_DEFAULT)) {
$newHash = password_hash($inputPwd, PASSWORD_DEFAULT);
$db->update('users', ['password' => $newHash], $row['id']);
}
算法或成本升级后,老用户登录时校验通过顺便重算哈希,平滑迁移不用强制改密。
错误做法对比
# 不要这样
md5($pwd); # 无盐,彩虹表秒破
sha1($pwd . $salt); # 自制盐方案,仍可GPU爆破
crypt($pwd); # 旧接口,参数难控
自己拼盐、用通用哈希函数存密码都是安全隐患,直接用内置密码函数。
注意事项
- 数据库密码字段长度留够60字符以上,bcrypt哈希约60位;
- 别自己实现加盐哈希,密码函数已封装随机盐和算法版本;
- 登录失败统一提示"用户名或密码错误",别区分哪个不存在;
- 密码强度前端后端双重校验,长度、复杂度、常见弱密码黑名单;
- 哈希不可逆,忘记密码只能重置,不能找回原密码;
- 配合HTTPS传输,密码在传输层也要加密保护。
总结
注册用password_hash生成bcrypt哈希入库,登录用password_verify校验,自带随机盐无需单独存盐。cost成本因子按服务器性能调整,password_needs_rehash在用户登录时平滑升级旧哈希。禁止用MD5、SHA1或自制盐方案存密码,密码字段预留60字符以上,登录失败提示统一,配合HTTPS和密码强度校验构成完整账号安全体系。