Yii默认使用bcrypt(CRYPT_BLOWFISH)生成密码哈希,哈希长度固定60字符、以$2y$开头,自动管理盐;验证必须用Security::validatePassword()而非password_verify(),以支持多算法兼容;可通过passwordHashAlgorithm配置切换算法,cost参数需根据服务器性能调优至0.05–0.25秒/次。

Yii 的 Security::generatePasswordHash() 默认用 bcrypt
Yii 2.0+ 的 Security 组件默认用 bcrypt(具体是 CRYPT_BLOWFISH),不是 MD5、SHA1 或 password_hash() 的默认 ARGON2I。它调用的是 PHP 底层的 crypt(),但封装后屏蔽了盐管理——你不用手动生成或存储盐。
常见错误现象:Security::generatePasswordHash('123') 输出类似 $2y$13$... 的字符串,有人误以为这是 base64 编码,试图解码;也有人拿它和 password_hash() 直接对比,发现算法标识不同就怀疑“不安全”。
- bcrypt 是 Yii 官方推荐且默认启用的,只要 PHP 版本 ≥ 5.5.0(建议 ≥ 7.2)就可用
- 哈希长度固定为 60 字符,开头
$2y$表示 bcrypt 版本(2y修复了早期2a在某些字符上的边界问题) - 如果服务器禁用了
crypt()(极少见),会退化到sha256+ 随机盐,但此时会抛出NotSupportedException,不会静默降级
验证密码必须用 Security::validatePassword(),别手写 password_verify()
虽然 Security::generatePasswordHash() 生成的是标准 bcrypt 格式,看起来能直接喂给 password_verify(),但 Yii 的验证逻辑不只是比对哈希——它还做了兼容性兜底:比如旧系统迁入时可能混着 md5 或 sha1 哈希,validatePassword() 会自动识别前缀并分发到对应校验逻辑。
常见错误现象:自己写 if (password_verify($input, $hash)) { ... },上线后发现老用户登录失败,因为部分历史哈希是 $2a$ 开头,而当前环境 PHP 的 password_verify() 对 2a 支持不稳定(尤其 PHP 7.0–7.1);或者更糟——有人把明文密码再哈希一次去比对,导致永远不匹配。
- 始终用
Yii::$app->security->validatePassword($password, $hash) - 该方法内部会解析
$hash开头(如$2y$、$2a$、$2x$、$1$等),再调用对应验证函数 - 如果你确认所有哈希都是现代 bcrypt,且不打算支持旧数据,那
password_verify()确实也能用,但失去 Yii 的统一抽象和未来升级弹性
想换算法?别改源码,用配置覆盖 Security::passwordHashAlgorithm
Yii 允许通过配置切换哈希算法,但不是靠重写 generatePasswordHash() 方法,而是设置 Security 组件的 passwordHashAlgorithm 属性。注意:这仅影响新生成的哈希,旧哈希仍靠 validatePassword() 兼容处理。
使用场景:合规要求强制使用 Argon2(PHP ≥ 7.2)、或测试环境想用更快的 sha256 加速 CI 流程。
- 在
config/web.php中配置:'components' => [ 'security' => [ 'class' => 'yii\base\Security', 'passwordHashAlgorithm' => PASSWORD_ARGON2I, 'passwordHashOptions' => ['memory_cost' => 65536, 'time_cost' => 4, 'threads' => 2], ], ] -
PASSWORD_ARGON2I和PASSWORD_ARGON2ID需要 PHP 编译时开启argon2扩展,否则运行时报错Unknown algorithm - 设成
PASSWORD_DEFAULT不推荐——它随 PHP 版本升级可能突变(如 PHP 8.0→8.1 切到 Argon2),线上哈希策略应显式锁定
哈希强度不能只看算法,cost 参数才是关键
bcrypt 的安全性不取决于“是不是 bcrypt”,而在于 cost 参数(即迭代轮数)。Yii 默认 cost = 13(约 0.1 秒/次),但这个值需根据你的服务器 CPU 调整:太低易被暴力破解,太高拖慢登录接口。
容易踩的坑:有人看到文档说“提高 cost 更安全”,就把 cost 改成 18,结果用户登录平均耗时 1.5 秒,大量超时投诉;也有人在 Docker 容器里没限制 CPU,压测时发现 cost=13 实际耗时只有 0.03 秒,等于裸奔。
- 用
Yii::$app->security->generatePasswordHash('test', 13)实测单次耗时(用microtime(true)包裹) - 生产环境建议控制在 0.05–0.25 秒之间;高并发登录服务可适当下调(如 12),后台管理可上调(如 14)
- 修改
cost后,新密码用新参数哈希,老密码仍按原参数验证——validatePassword()会从哈希字符串里自动提取原始 cost 值
真正麻烦的是迁移:如果想把全库旧密码用更高 cost 重哈希,得等用户下次登录时再更新,没法批量刷——因为没明文。这事没捷径,只能接受渐进式升级。


















