Skip to content

密码散列算法

PHP 提供了 password_hash()password_verify() 函数,用于安全地存储和验证用户密码。这两个函数内置了盐值生成、算法选择和自适应成本因子,是 PHP 中密码存储的最佳实践。

前置知识

阅读本节前,建议先了解:Hash 扩展Sodium 扩展

password_hash

php
<?php
declare(strict_types=1);

// 对密码进行哈希
$password = 'MySecurePassword123!';
$hash = password_hash($password, PASSWORD_BCRYPT);

echo "哈希值: {$hash}" . PHP_EOL;
// 输出类似: $2y$10$N9qo8uLOickgx2ZMRZoMy...

算法常量

php
<?php
declare(strict_types=1);

// PASSWORD_BCRYPT - bcrypt 算法(默认)
$hash = password_hash($password, PASSWORD_BCRYPT);

// PASSWORD_ARGON2ID - Argon2id 算法(PHP 7.3+,推荐)
$hash = password_hash($password, PASSWORD_ARGON2ID);

// PASSWORD_ARGON2I - Argon2i 算法(PHP 7.3+)
$hash = password_hash($password, PASSWORD_ARGON2I);

// PASSWORD_DEFAULT - 默认算法(随 PHP 版本变化)
$hash = password_hash($password, PASSWORD_DEFAULT);

自定义选项

php
<?php
declare(strict_types=1);

// Bcrypt 选项
$options = [
    'cost' => 12,  // 成本因子(4~31,越高越安全但越慢)
];
$hash = password_hash($password, PASSWORD_BCRYPT, $options);

// Argon2id 选项
$options = [
    'memory_cost'  => 65536,   // 内存成本(KB),默认 65536
    'time_cost'   => 4,        // 时间成本,默认 4
    'threads'     => 1,        // 并行线程数,默认 1
];
$hash = password_hash($password, PASSWORD_ARGON2ID, $options);

password_verify

php
<?php
declare(strict_types=1);

// 用户登录验证
function verifyLogin(string $inputPassword, string $storedHash): bool
{
    return password_verify($inputPassword, $storedHash);
}

// 使用示例
$storedHash = '$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy';

if (verifyLogin('MySecurePassword123!', $storedHash)) {
    echo "登录成功" . PHP_EOL;
} else {
    echo "密码错误" . PHP_EOL;
}

password_needs_rehash

php
<?php
declare(strict_types=1);

// 检查是否需要更新哈希(当算法或成本因子变化时)
function checkAndRehash(string $password, string $hash): ?string
{
    if (password_needs_rehash($hash, PASSWORD_ARGON2ID)) {
        echo "密码哈希需要更新" . PHP_EOL;
        return password_hash($password, PASSWORD_ARGON2ID);
    }
    return null;
}

// 使用示例
// $user->password_hash = checkAndRehash($inputPassword, $user->password_hash);

注意事项

  • 永远不要自己实现密码哈希,使用 password_hash()
  • 不要使用 MD5/SHA1 存储密码
  • cost 参数越高越安全,但会增加计算时间
  • 使用 password_needs_rehash 在登录时更新哈希

下一节

继续学习:DateTime 类

参考链接