PHP项目怎样实现密码加密存储?

wen PHP项目 10

本文目录导读:

PHP项目怎样实现密码加密存储?

  1. 核心函数:密码加密与验证
  2. 数据库设计
  3. 进阶:使用更现代的 Argon2 算法
  4. 最佳实践
  5. 总结示例代码

在PHP项目中实现密码加密存储,千万不要使用 md5()sha1() 这类简单哈希函数,因为它们已经不再安全。

目前最推荐、最安全的方法是使用 PHP 内置的 password_hash() 函数和 password_verify() 函数,PHP 默认使用 bcrypt 算法,这是目前最主流的密码哈希算法。

以下是详细的实现步骤和最佳实践。


核心函数:密码加密与验证

1 注册时:生成密码哈希

使用 password_hash() 对用户输入的密码进行加密。

<?php
// 用户注册时提交的密码
$plainPassword = $_POST['password'] ?? '';
// 使用 bcrypt 算法生成哈希(默认成本系数为 10)
$hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT);
// 将 $hashedPassword 存储到数据库(varchar(255) 足够)
// INSERT INTO users (username, password) VALUES ('某个用户名', '$hashedPassword');
echo $hashedPassword; // $2y$10$SomeSaltAndHash...
?>
  • PASSWORD_BCRYPT:指定使用 bcrypt 算法。
  • PASSWORD_DEFAULT:推荐选项,它会使用当前 PHP 版本推荐的最强算法(目前是 bcrypt,未来可能是 Argon2),使用这个选项,代码在未来 PHP 版本升级时能自动使用更强的算法。
  • $hashedPassword:包含算法、盐(盐是自动随机生成的)和哈希值的字符串。非常安全

2 登录时:验证密码

使用 password_verify() 比对用户输入的密码与数据库中存储的哈希值。

<?php
// 用户登录时输入密码
$inputPassword = $_POST['password'] ?? '';
// 从数据库读取该用户的哈希密码(假设从数据库查询得到)
$storedHash = '$2y$10$SomeSaltAndHash...'; // 数据库中的值
// 验证密码
if (password_verify($inputPassword, $storedHash)) {
    // 密码正确,登录成功
    echo "登录成功!";
    // 启动 session,跳转页面等
} else {
    // 密码错误
    echo "密码错误!";
}
?>
  • password_verify() 自动从存储的哈希值中提取出算法、成本因子和盐,然后对输入的密码进行同样的哈希计算,最后比较结果,整个过程安全且透明。

数据库设计

创建一个 users 表来存储用户信息,password 字段需要足够长来容纳哈希字符串。

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,   -- 存储哈希值,长度必须至少 60(bcrypt 的输出为 60 个字符),建议 255 以兼容未来算法
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

进阶:使用更现代的 Argon2 算法

PHP 7.2+ 支持 Argon2 算法,它比 bcrypt 更先进、更抗 GPU 和 ASIC 攻击。

<?php
// 使用 Argon2 算法(PHP 7.2+ 需要安装 libsodium 或使用 PHP 编译的 --with-password-argon2 选项)
$hashedPassword = password_hash($plainPassword, PASSWORD_ARGON2I);
// 或者使用 Argon2id (PHP 7.3+ 推荐,兼顾抗侧信道攻击和抗 GPU 攻击)
$hashedPassword = password_hash($plainPassword, PASSWORD_ARGON2ID);
// 验证方式完全一样
if (password_verify($inputPassword, $storedHash)) {
    // 密码正确
}
  • 如果你不确定服务器是否支持 Argon2,使用 PASSWORD_DEFAULT 是安全的选择,PHP 版本默认算法切换为 Argon2 时,你的代码会自动适应。

最佳实践

  1. 永远不要在数据库中存储明文密码。

  2. 使用 password_hash()password_verify(),不要自己拼接盐或使用 md5sha1sha256

  3. password_hash() 设置合适的 cost 因子(bcrypt 的成本系数,控制哈希计算速度)。

    • 默认是 10(约 0.1 秒)。
    • 如果你希望更慢一点(增加破解成本),可以调高,12
      $options = ['cost' => 12];
      $hashedPassword = password_hash($plainPassword, PASSWORD_BCRYPT, $options);
    • 注意:成本太高会影响用户体验(登录变慢),建议根据你的服务器性能,将哈希计算时间控制在 1 - 0.5 秒之间。
  4. 如果需要升级哈希算法或成本因子(例如将成本从 10 升级到 12),可以在用户登录成功时,用新的算法重新对其密码进行哈希,然后更新数据库,这就是 密码哈希重哈希

    if (password_verify($inputPassword, $storedHash)) {
        // 如果当前哈希不是用最新算法或最优成本因子
        if (password_needs_rehash($storedHash, PASSWORD_DEFAULT, ['cost' => 12])) {
            $newHash = password_hash($inputPassword, PASSWORD_DEFAULT, ['cost' => 12]);
            // 更新数据库:UPDATE users SET password = '$newHash' WHERE id = $userId;
        }
        // 登录成功
    }
  5. 使用 HTTPS,密码在传输过程中必须是加密的,否则即使服务器存储很安全,中间人攻击也能获取明文密码。

  6. 输入长度限制:在客户端(HTML)和服务器端对密码长度进行合理限制(例如最长 64 或 72 个字符,因为 bcrypt 内部处理 72 字节),这可以防止恶意用户提交超长密码导致拒绝服务攻击(DOS)。


总结示例代码

注册处理(register.php)

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'] ?? '';
    $plainPassword = $_POST['password'] ?? '';
    // 验证输入...
    if (strlen($plainPassword) < 8) {
        die("密码不能少于8个字符");
    }
    // 生成密码哈希
    $hashedPassword = password_hash($plainPassword, PASSWORD_DEFAULT);
    // 插入数据库(使用 PDO 预处理语句)
    // $stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
    // $stmt->execute([$username, $hashedPassword]);
    echo "注册成功!";
}
?>

登录处理(login.php)

<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'] ?? '';
    $inputPassword = $_POST['password'] ?? '';
    // 从数据库查询用户(使用 PDO 预处理语句)
    // $stmt = $pdo->prepare("SELECT id, password FROM users WHERE username = ?");
    // $stmt->execute([$username]);
    // $user = $stmt->fetch();
    if ($user && password_verify($inputPassword, $user['password'])) {
        // 可选:检查是否需要更新哈希
        if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) {
            $newHash = password_hash($inputPassword, PASSWORD_DEFAULT);
            // 更新数据库...
        }
        $_SESSION['user_id'] = $user['id'];
        header('Location: dashboard.php');
        exit;
    } else {
        echo "用户名或密码错误";
    }
}
?>

通过以上方法,你的 PHP 项目就能实现安全、现代、符合业界标准的密码加密存储。

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