应使用 encryptByKey 和 decryptByKey 进行对称加解密,而非 encrypt/decrypt;密码哈希必须用 generatePasswordHash 和 validatePassword;hashData 仅适用于防篡改签名且需手动管理 salt。

加密解密用 encryptByKey 和 decryptByKey,别碰 encrypt/decrypt
Yii 的 Security 组件默认不提供“密码学安全”的对称加解密接口,encrypt 和 decrypt 是为 Cookie 签名/加密设计的内部方法,硬用会导致密钥管理混乱、无法跨版本解密,甚至触发 InvalidParamException 错误。
正确做法是走 encryptByKey(AES-128-CBC,默认)+ decryptByKey,它接受明文、密钥和可选 IV:
use yii\base\Security; $security = new Security(); $key = '32-byte-secret-key-must-be-exactly-this-long'; // 必须 32 字节 $plaintext = 'hello world'; $ciphertext = $security->encryptByKey($plaintext, $key); $decrypted = $security->decryptByKey($ciphertext, $key); // 成功返回 'hello world'
-
encryptByKey默认生成随机 IV 并前置到密文开头(base64 后),decryptByKey会自动拆分——别自己拼 IV - 密钥长度必须严格匹配算法:AES-128 要 16 字节,AES-256 要 32 字节;传错长度会静默降级或报
InvalidParamException - 密文是二进制数据,存数据库或传 HTTP 时务必
base64_encode;反过来解密前要base64_decode
哈希密码用 generatePasswordHash + validatePassword,不是 hashData
存用户密码必须用 PBKDF2(Yii 默认),而不是通用哈希函数。直接调 hashData 得到的是不可逆但无盐、无迭代的哈希,等于裸奔。
generatePasswordHash 自动生成随机 salt、固定 10 万次迭代(可配),输出格式为 y$...(bcrypt 兼容格式):
$hash = $security->generatePasswordHash('my-pass-123');
// 输出类似:$2y$13$ZzFmYzEwZjMxZDQyYzQyY.9uUzIzZjMxZDQyYzQyYzQyYzQyY
-
validatePassword自动解析 hash 中的 salt 和 cost,无需你传参——传错参数反而会跳过校验逻辑 - 不要自己拼
crypt()或调hash('sha256', ...),这类哈希无法抵御彩虹表或 GPU 暴力破解 - 如果旧系统用了其他算法(如 bcrypt 原生 hash),
validatePassword仍能兼容验证,但迁移时别覆盖原 hash
敏感数据加盐哈希用 hashData,但必须手动管 salt
hashData 适合做「防篡改」签名,比如生成带时效的下载链接 token,或校验配置项是否被修改。它不是密码哈希工具,也不自动加盐。
- 必须显式传 salt:
$security->hashData($data, $secretKey),其中$secretKey就是 salt,要保密且固定 - 输出是 base64 编码的 HMAC-SHA256,长度固定 44 字符;验证用
validateData,它会自动重算并比对 - 别用它存密码——没迭代、没随机 salt,
hashData('123', 'salt')在毫秒级就能被撞库 - Web 应用里常见误用:把用户 ID 直接
hashData($id, $key)当 token 用,结果 key 泄露就全盘崩坏
注意 Yii 版本差异:2.x 和 3.x 的 Security 不兼容
Yii 2.0 的 Security 类在 yii\base\Security,而 Yii 3.0 拆到了 yii\security\Security,且默认算法不同:
- Yii 2.0:
encryptByKey默认 AES-128-CBC;generatePasswordHash默认 PBKDF2-SHA256 - Yii 3.0:
encryptByKey默认 AES-256-CBC;generatePasswordHash默认使用password_hash()(bcrypt) - 跨版本迁移加密数据?不行。密文结构、IV 处理、密钥派生逻辑全变了,必须重新加解密
- 升级前检查所有
encryptByKey调用点——尤其是密钥长度和是否手动处理了 IV
最麻烦的不是 API 变了,而是加密结果不可逆兼容。线上有存量密文的话,得留双轨逻辑跑一段时间。


















