用户注册时对密码加盐存储,是防止彩虹表攻击、提升系统安全性的基本做法。PHP中实现密码加盐的核心方式是使用 password_hash() 和 password_verify() 函数,它们自动处理盐值的生成与验证,无需手动管理。
1. 注册时密码加盐存储
用户注册时,不能明文保存密码。应使用 password_hash() 生成带盐的哈希值:
- 该函数内部自动生成唯一盐值,每次调用结果都不同
- 推荐使用
PASSWORD_DEFAULT,当前对应 bcrypt 算法
- 哈希字符串中已包含算法、成本因子和盐值,直接存入数据库即可
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
// 存入数据库
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->execute([$username, $hashedPassword]);
2. 盐值如何生成与存储
开发者无需手动生成或存储盐值,password_hash() 已自动完成:
- 每次调用都会生成新的随机盐
- 生成的哈希字符串格式为:
$algorithm$cost$salt$hash
- 例如:
$2y$10$abcdefghijk1234567890euKjBzJ2qO9W1mNc3pRtS
- 整个字符串可直接存入数据库的 password 字段(建议字段长度至少 255)
3. 登录时密码验证流程
用户登录时,使用 password_verify() 验证明文密码与存储哈希是否匹配:
- 函数会自动提取存储哈希中的盐和算法参数
- 用相同方式重新计算哈希并比对
- 返回布尔值,匹配则登录成功
// 查询用户
$stmt = $pdo->prepare("SELECT passwo
rd FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
echo "登录成功";
// 启动 session 或生成 token
} else {
echo "用户名或密码错误";
}
4. 安全建议与注意事项
虽然 PHP 内置函数简化了加盐流程,但仍需注意以下几点:
- 永远不要自己实现加密逻辑,坚持使用 password_hash() 和 password_verify()
- 数据库字段要足够长(VARCHAR(255))以容纳哈希字符串
- 可调整成本因子提高安全性(默认 cost=10,可设为11-12,但别过高影响性能)
- 定期更新哈希:可通过 password_needs_rehash() 检查是否需要重新加密
if (password_needs_rehash($user['password'], PASSWORD_DEFAULT, ['cost' => 12])) {
$newHash = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]);
// 更新数据库中的密码哈希
}
基本上就这些。PHP 的密码哈希函数已经把盐值管理做得非常完善,开发者只需正确调用,就能实现安全的用户认证机制。