YII2加密内容
Yii 框架(Yii 2.x 为主,Yii 1.x 类似)提供了 安全可靠的加密方案,核心基于 PHP 的 openssl 扩展,支持对称加密(AES)、哈希加密(密码存储)、数据签名等场景。以下是 Yii 中常用加密方式的完整实现(含示例、配置、注意事项):
一、核心加密方式分类
Yii 的加密主要分为 3 类场景,对应不同需求:
| 场景 | 推荐方案 | 用途 |
|---|---|---|
| 密码存储(不可逆) | Yii::$app->security->generatePasswordHash() | 用户密码存储(不可解密) |
| 数据加密(可逆) | Yii::$app->security->encryptByKey()(AES) | 敏感数据加密(如手机号、身份证) |
| 数据签名(防篡改) | Yii::$app->security->signData() | 验证数据完整性(如接口参数) |
二、1. 密码存储(不可逆加密,推荐)
用户密码绝不能明文存储,Yii 提供 generatePasswordHash() 生成哈希值(基于 Bcrypt/Argon2,自动加盐,安全可靠),配合 validatePassword() 验证。
用法示例
1. 密码加密(注册/修改密码时)
// 原始密码(用户输入)
$rawPassword = '123456Aa!';
// 生成加密哈希(自动加盐,无需手动处理盐值)
$hashedPassword = Yii::$app->security->generatePasswordHash($rawPassword);
// 存储到数据库(如 user 表的 password 字段)
$user = new User();
$user->username = 'test';
$user->password = $hashedPassword; // 存储的是哈希值,不是明文
$user->save();2. 密码验证(登录时)
// 用户登录输入的密码
$inputPassword = '123456Aa!';
// 从数据库查询用户存储的哈希密码
$user = User::findOne(['username' => 'test']);
// 验证输入密码是否匹配哈希值
if ($user && Yii::$app->security->validatePassword($inputPassword, $user->password)) {
echo "登录成功";
} else {
echo "密码错误";
}关键说明
- 无需手动管理盐值:
generatePasswordHash()会自动生成随机盐值,并嵌入到哈希结果中(验证时自动提取盐值)。 - 算法选择:优先使用 Argon2(PHP 7.2+ 支持),其次是 Bcrypt,均为行业安全标准。
- 哈希长度:结果约 60 字符,数据库
password字段建议设为VARCHAR(255)(预留扩展空间)。
三、2. 数据可逆加密(AES 加密,支持解密)
用于加密敏感数据(如手机号、身份证号、订单号),加密后可通过密钥解密还原原始数据。Yii 推荐用 encryptByKey() 和 decryptByKey()(基于 AES-256-GCM 算法,带认证标签,防篡改)。
前置配置(关键!)
加密依赖 密钥(key) 和 加密向量(IV),需在 Yii 配置文件中设置安全密钥(config/web.php 或 config/main.php):
return [
'components' => [
'security' => [
'key' => '你的安全密钥(至少32字节,推荐64字节)',
// 密钥生成方式:在终端执行 `php yii security/generate-random-string 64` 生成随机密钥
],
],
];- 密钥生成:执行
php yii security/generate-random-string 64生成 64 字节的安全随机密钥(切勿硬编码简单字符串,如123456)。 密钥安全:密钥需保密,生产环境建议通过环境变量注入(避免提交到代码仓库):
'key' => getenv('YII_SECURITY_KEY'), // 从环境变量读取
用法示例
1. 加密数据
// 原始敏感数据(字符串类型)
$rawData = '13812345678'; // 手机号示例
// 加密(自动生成 IV,嵌入到加密结果中)
$encryptedData = Yii::$app->security->encryptByKey($rawData, Yii::$app->security->key);
// 加密结果是二进制字符串,建议转为 Base64 存储(方便数据库存储和传输)
$encryptedBase64 = base64_encode($encryptedData);
// 存储到数据库(字段类型设为 VARCHAR 或 TEXT)
$user->phone_encrypted = $encryptedBase64;
$user->save();2. 解密数据
// 从数据库读取加密后的 Base64 字符串
$encryptedBase64 = $user->phone_encrypted;
// 先解码 Base64
$encryptedData = base64_decode($encryptedBase64);
// 解密(自动提取 IV 和认证标签,验证数据完整性)
try {
$decryptedData = Yii::$app->security->decryptByKey($encryptedData, Yii::$app->security->key);
echo "解密结果:" . $decryptedData; // 输出:13812345678
} catch (yii\base\InvalidArgumentException $e) {
// 解密失败(数据被篡改、密钥错误、加密格式错误)
echo "解密失败:" . $e->getMessage();
}进阶:自定义加密参数
如果需要自定义算法、IV 等(不推荐默认以外的配置):
// 自定义 IV(需 16 字节,AES-256-GCM 要求)
$iv = Yii::$app->security->generateRandomString(16);
// 加密(指定 IV 和算法)
$encryptedData = Yii::$app->security->encryptByKey(
$rawData,
Yii::$app->security->key,
$iv,
'aes-256-gcm' // 支持的算法:aes-128-gcm、aes-192-gcm、aes-256-gcm
);
// 解密时需传入相同的 IV
$decryptedData = Yii::$app->security->decryptByKey($encryptedData, Yii::$app->security->key, $iv);关键说明
- 加密结果是二进制:必须转为 Base64 或 Hex 存储(否则数据库可能截断或乱码)。
- 防篡改:AES-GCM 算法自带认证标签,数据被篡改后会解密失败(抛出异常)。
- 密钥不可变更:一旦密钥丢失或变更,已加密的数据无法解密,需提前备份密钥。
四、3. 数据签名(防篡改,不加密)
用于验证数据是否被篡改(如接口参数、敏感配置),签名后数据明文传输,但接收方可通过签名验证完整性。核心是 signData() 和 validateData()(基于 HMAC-SHA256)。
用法示例
1. 生成数据签名
// 原始数据(可以是数组、字符串)
$data = [
'user_id' => 1001,
'order_id' => 'OD20251113001',
'amount' => 99.9,
];
// 生成签名(基于密钥,数据变化则签名失效)
$signature = Yii::$app->security->signData(
json_encode($data), // 数组需转为字符串
Yii::$app->security->key,
'sha256' // 签名算法:sha256、sha512 等
);
// 传输时携带数据和签名(如接口参数)
$requestParams = [
'data' => json_encode($data),
'signature' => $signature,
];2. 验证签名(接收方)
// 接收接口参数
$receivedData = $_GET['data'];
$receivedSignature = $_GET['signature'];
try {
// 验证签名(签名无效会抛出异常)
$validatedData = Yii::$app->security->validateData(
$receivedData,
$receivedSignature,
Yii::$app->security->key,
'sha256'
);
// 签名验证通过,解析数据
$data = json_decode($validatedData, true);
echo "数据有效:" . print_r($data, true);
} catch (yii\base\InvalidArgumentException $e) {
echo "数据被篡改或签名无效:" . $e->getMessage();
}关键说明
- 签名不加密数据:仅验证完整性,数据明文可见,适合无需保密但需防篡改的场景。
- 签名依赖密钥:接收方需持有相同密钥才能验证,密钥需保密。
五、4. 其他常用加密工具
1. 生成随机字符串(盐值、验证码等)
// 生成 16 字节的随机字符串(二进制)
$randomBytes = Yii::$app->security->generateRandomString(16);
// 生成 32 位的随机字符串(Base64 编码,可直接用于token)
$randomToken = Yii::$app->security->generateRandomString(32);2. 哈希函数(MD5/SHA1 等,不推荐密码存储)
// SHA256 哈希(需手动加盐,不如 password_hash 安全)
$hash = Yii::$app->security->hashData($rawData, '盐值', 'sha256');
// 验证哈希
$isValid = Yii::$app->security->validateData($rawData, $hash, '盐值', 'sha256');- 注意:
hashData()不适合密码存储(盐值需手动管理),仅用于非敏感数据的哈希验证。
六、生产环境安全建议
密钥安全:
- 切勿硬编码密钥到代码中,通过环境变量(如
YII_SECURITY_KEY)或配置文件(.env)注入。 - 密钥至少 32 字节(AES-256 要求),定期备份密钥(丢失则无法解密数据)。
- 切勿硬编码密钥到代码中,通过环境变量(如
加密算法:
- 优先使用 Yii 默认算法(AES-256-GCM、Bcrypt/Argon2),不自定义弱算法(如 DES、MD5)。
数据存储:
- 加密后的数据建议用
VARCHAR(512)或TEXT存储(Base64 编码后长度会增加约 1/3)。 - 敏感数据字段(如身份证、手机号)加密后,避免明文日志打印。
- 加密后的数据建议用
扩展依赖:
- 确保 PHP 启用
openssl扩展(Yii 加密的核心依赖),可通过phpinfo()验证。
- 确保 PHP 启用
版本要求:
- Yii 2.0.13+ 支持 AES-GCM 算法,建议升级到最新稳定版(修复安全漏洞)。
七、常见问题排查
解密失败:
- 密钥不匹配:加密和解密必须使用相同密钥。
- 数据格式错误:加密后未转 Base64 存储,导致数据截断。
- 数据被篡改:AES-GCM 验证失败,需检查数据完整性。
密码验证失败:
- 明文密码前后有空格:需用
trim()处理用户输入。 - 哈希算法不兼容:旧版本 Yii 可能用 Bcrypt,新版本兼容,但需确保 PHP 支持对应算法。
- 明文密码前后有空格:需用
openssl 扩展未启用:
- 报错:
Call to undefined function openssl_encrypt(),需在php.ini中启用extension=openssl。
- 报错:
根据你的场景选择对应加密方式:密码存储用 密码哈希,敏感数据可逆加密用 AES,防篡改用 数据签名。如果需要结合具体业务(如接口加密、用户数据脱敏),可以告诉我详细需求,帮你细化代码!
版权属于:Joyber
本文链接:https://blog.qqvbc.com/default/1386.html
转载时须注明出处及本声明