PHP 怎么PHP Bcrypt

wen PHP项目 2

PHP中如何使用Bcrypt进行密码哈希与验证(全指南)

📖 目录导读

  • Bcrypt是什么?为什么PHP开发者必须掌握?

    PHP 怎么PHP Bcrypt

    1. PHP中Bcrypt的核心函数:password_hash()password_verify()
  • 实战:如何用Bcrypt生成安全哈希密码?

  • 验证密码:从用户登录到哈希对比

  • Bcrypt的成本系数(Cost Factor)如何调优?

  • 常见错误与安全陷阱(含问答)

  • 与其他哈希算法对比:MD5、SHA256为何被淘汰?

  • 经典问答:Bcrypt与password_needs_rehash()的深度用法


Bcrypt是什么?为什么PHP开发者必须掌握?

Bcrypt是一种基于Blowfish加密算法的密码哈希函数,专为密码存储而设计,它通过引入可调成本因子(Cost Factor),让暴力破解的计算成本随着硬件发展而线性增长,在PHP生态中,从5.5.0版本开始官方内置了password_hash()函数,默认使用Bcrypt算法。

为什么必须用Bcrypt?

  • 内置Salt:每次生成哈希时自动随机添加高熵值加盐。
  • 自适应慢速:默认成本因子10,单次哈希约需0.1秒,暴力破解效率极低。
  • 抗彩虹表:动态加盐使预先计算失效。

重要提示:绝不要使用MD5、SHA1、甚至SHA256直接存储密码,这些算法在毫秒级即可完成计算,极易被GPU加速破解。


PHP中Bcrypt的核心函数:password_hash()password_verify()

PHP官方推荐使用这两个函数操作Bcrypt,无需手动生成salt或设置复杂参数。

// 生成哈希
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// 验证密码
if (password_verify($input_password, $stored_hash)) {
    echo "密码正确";
}

关键参数说明

  • PASSWORD_BCRYPT:指定算法为Bcrypt。
  • cost:默认10,范围4~31,数值越高计算越慢。
  • 自动输出的哈希格式: $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    • $2y 表示Bcrypt版本
    • 10 表示成本系数
    • 后面是22字符的Salt + 31字符的真正哈希

实战:如何用Bcrypt生成安全哈希密码?

注册时生成哈希

$user_password = $_POST['password'];
$options = ['cost' => 12];  // 根据服务器性能调整
$hashed_password = password_hash($user_password, PASSWORD_BCRYPT, $options);
// 将$hashed_password存入数据库,字段长度建议60~255字符

数据库存储建议

  • 字段类型:VARCHAR(255)CHAR(60)
  • 字符集:utf8mb4ascii(避免字符转换问题)

验证时间测试
在开发环境中,可根据CPU负载调整cost

$start = microtime(true);
password_hash("test", PASSWORD_BCRYPT, ['cost' => 12]);
echo microtime(true) - $start; // 输出:约0.25~0.5秒

验证密码:从用户登录到哈希对比

当用户登录时,从数据库取出哈希值,调用password_verify()

$stored_hash = "从数据库查询的哈希值";
$user_input = $_POST['password'];
if (password_verify($user_input, $stored_hash)) {
    // 登录成功,生成session
    $_SESSION['user_id'] = $user_id;
} else {
    // 登录失败,返回错误
}

注意password_verify()会自动解析哈希中的cost和salt,无需手动匹配。


Bcrypt的成本系数(Cost Factor)如何调优?

成本系数决定计算时间,调优原则:

  • 基准测试:使单次哈希耗时在 1~0.5秒 之间(视业务并发量)。
  • 硬件考量:云服务器选cost=10~12;老式硬件选cost=8~10。
  • 安全趋势:2025年后建议cost≥12。

示例调优代码:

function findOptimalCost($target_time = 0.3) {
    $cost = 8;
    do {
        $cost++;
        $start = microtime(true);
        password_hash("test", PASSWORD_BCRYPT, ['cost' => $cost]);
        $elapsed = microtime(true) - $start;
    } while ($elapsed < $target_time && $cost < 31);
    return $cost;
}
// 执行得到推荐cost值

常见错误与安全陷阱(含问答)

❌ 误区1:手动加盐
password_hash()已内置强盐,不要自行拼接salt,否则导致哈希格式错误。

❌ 误区2:截断存储
Bcrypt哈希最长60字符,但数据库字段若设为VARCHAR(50)会截断,导致验证失败,请用VARCHAR(255)

❌ 误区3:使用crypt()直接操作Bcrypt
crypt()需要手动构造salt字符串,极易出错,请优先使用password_hash()

❌ 误区4:忽略密码长度限制
Bcrypt默认只处理前72个字符,超过部分被忽略,需在前端或后端做长度校验(72字符以内或警告用户)。


与其他哈希算法对比:MD5、SHA256为何被淘汰?

算法 哈希时间(成本10) 是否内置加盐 暴力破解防御性
MD5 <0.001秒 极低(GPU每秒100亿次)
SHA256 <0.001秒 低(可ASIC加速)
bcrypt(cost=10) ~0.1秒 ✅ 自动 高(无法硬件加速)
bcrypt(cost=12) ~0.4秒 ✅ 自动 极高

2025年的安全标准下,任何非自适应算法(包括SHA256迭代10000次)都已被证明不安全,唯一推荐的是Bcrypt、Argon2(PHP 7.2+支持)。


经典问答:Bcrypt与password_needs_rehash()的深度用法

Q1:如果未来提升cost值,如何更新现有密码?
A:使用password_needs_rehash()检测哈希是否需要重新生成:

if (password_verify($input, $existing_hash)) {
    if (password_needs_rehash($existing_hash, PASSWORD_BCRYPT, ['cost' => 12])) {
        $new_hash = password_hash($input, PASSWORD_BCRYPT, ['cost' => 12]);
        // 更新数据库中的哈希
    }
    // 登录成功
}

此方法在用户登录时渐进式更新,无需强制所有用户重置密码。

Q2:如何从Bcrypt迁移到Argon2?
A:首先保持两个算法并存,登录验证后检测算法并升级:

if (password_verify($input, $hash)) {
    // 如果当前使用Bcrypt,升级到Argon2
    if (password_get_info($hash)['algo'] !== PASSWORD_ARGON2ID) {
        $new_hash = password_hash($input, PASSWORD_ARGON2ID);
        // 更新数据库
    }
}

Q3:哈希结果中有$2y$$2a$版本差异?
A:$2y$是PHP 5.5+修复错误后的版本,$2a$只在老旧系统中出现。password_hash()始终生成$2y$,兼容性更好。

Q4:密码也可以使用Bcrypt对非密码场景做哈希吗?
A:不建议,Bcrypt设计用于密码且速度慢,普通数据哈希应用SHA256+随机盐,速度优先。



Bcrypt是PHP开发者保护用户密码的基石,通过password_hash()password_verify()确保了实现的正确性,同时灵活调整cost因子可以平衡安全性与性能,请务必抛弃老旧算法,并利用password_needs_rehash()保持未来兼容性,为了深入掌握,建议在测试环境中运行本文示例代码,观察不同cost值对响应时间的影响。

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