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.phpconfig/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() 不适合密码存储(盐值需手动管理),仅用于非敏感数据的哈希验证。

六、生产环境安全建议

  1. 密钥安全

    • 切勿硬编码密钥到代码中,通过环境变量(如 YII_SECURITY_KEY)或配置文件(.env)注入。
    • 密钥至少 32 字节(AES-256 要求),定期备份密钥(丢失则无法解密数据)。
  2. 加密算法

    • 优先使用 Yii 默认算法(AES-256-GCM、Bcrypt/Argon2),不自定义弱算法(如 DES、MD5)。
  3. 数据存储

    • 加密后的数据建议用 VARCHAR(512)TEXT 存储(Base64 编码后长度会增加约 1/3)。
    • 敏感数据字段(如身份证、手机号)加密后,避免明文日志打印。
  4. 扩展依赖

    • 确保 PHP 启用 openssl 扩展(Yii 加密的核心依赖),可通过 phpinfo() 验证。
  5. 版本要求

    • Yii 2.0.13+ 支持 AES-GCM 算法,建议升级到最新稳定版(修复安全漏洞)。

七、常见问题排查

  1. 解密失败

    • 密钥不匹配:加密和解密必须使用相同密钥。
    • 数据格式错误:加密后未转 Base64 存储,导致数据截断。
    • 数据被篡改:AES-GCM 验证失败,需检查数据完整性。
  2. 密码验证失败

    • 明文密码前后有空格:需用 trim() 处理用户输入。
    • 哈希算法不兼容:旧版本 Yii 可能用 Bcrypt,新版本兼容,但需确保 PHP 支持对应算法。
  3. openssl 扩展未启用

    • 报错:Call to undefined function openssl_encrypt(),需在 php.ini 中启用 extension=openssl

根据你的场景选择对应加密方式:密码存储用 密码哈希,敏感数据可逆加密用 AES,防篡改用 数据签名。如果需要结合具体业务(如接口加密、用户数据脱敏),可以告诉我详细需求,帮你细化代码!

标签: none

添加新评论