PHP项目登录密码如何加密存储

wen PHP项目 21

本文目录导读:

PHP项目登录密码如何加密存储

  1. 推荐方法:使用 password_hash()password_verify()
  2. 更安全的选择:Argon2i / Argon2id
  3. 需要重新计算哈希吗?(密码时效检查)
  4. ⚠️ 常见错误(不要这样做)
  5. 数据库字段设计
  6. 扩展:盐值(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_costtime_cost等(对Argon2)实现的。
  • 算法可以升级,无需修改现有密码。

更安全的选择:Argon2i / Argon2id

如果你的PHP版本 >= 7.2,可以使用Argon2iArgon2id算法,它比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) 同样不安全
自行拼接盐值 容易设计出错,且无法自动升级算法
双向加密(AESbase64 密码不需要解密,只需要验证
把密码存在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)。

抱歉,评论功能暂时关闭!