本文目录导读:

- 核心结论(选型总结)
- 绝对首选:AES-256-GCM(推荐)
- 次选方案:AES-256-CBC + HMAC(兼容旧环境)
- 密钥管理(比算法更重要)
- 防坑指南(注意事项)
- 终极替代方案:现代加密库(libsodium)
- 最终决策树
在 PHP 中进行对称加密,首选方案是 openssl_encrypt / openssl_decrypt,结合 AES-256-GCM 模式。
以下是详细的选型指南、代码示例及安全注意事项。
核心结论(选型总结)
| 算法/模式 | 推荐度 | 说明 |
|---|---|---|
| AES-256-GCM | ⭐⭐⭐⭐⭐ | 首选,提供认证加密(AEAD),防止密文被篡改,性能优秀,PHP 7.1+ 原生支持。 |
| AES-256-CBC + HMAC-SHA256 | ⭐⭐⭐⭐ | 次选,若环境不支持 GCM(如老版本),用于在不支持 AEAD 时实现"加密+签名"。 |
| AES-256-CTR | ⭐⭐⭐ | 流模式,无填充,但必须配合 HMAC,否则不安全。 |
mcrypt |
❌ 弃用 | PHP 7.1 已废弃,7.2 移除,严禁使用。 |
Sodium |
⭐⭐⭐⭐⭐ | PHP 7.2+ 内置,现代加密库(libsodium),但 API 相对底层。 |
绝对首选:AES-256-GCM(推荐)
GCM 模式在加密的同时自动生成认证标签(Tag),解密时若不提供正确的 TAG 会直接失败,防止"填充预言攻击"。
示例代码(PHP 7.1+)
<?php
/**
* AES-256-GCM 加密
* @param string $plaintext 明文
* @param string $key 密钥(必须是 32 字节,建议用 hash('sha256', $password, true) 派生)
* @return array [密文, IV, TAG]
*/
function aes_gcm_encrypt(string $plaintext, string $key): array {
// 生成随机 IV(推荐 12 字节,GCM 标准长度)
$iv = random_bytes(12);
// 加密并生成认证标签(TAG)
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA, // 不进行 Base64 编码,直接返回原始二进制
$iv,
$tag // 16 字节的认证标签
);
return [$ciphertext, $iv, $tag];
}
/**
* AES-256-GCM 解密
* @param string $ciphertext 密文
* @param string $iv IV
* @param string $tag 认证标签
* @param string $key 密钥
* @return string|false 明文,验证失败返回 false
*/
function aes_gcm_decrypt(string $ciphertext, string $iv, string $tag, string $key) {
$plaintext = openssl_decrypt(
$ciphertext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
return $plaintext;
}
// --- 使用示例 ---
$key = hash('sha256', '很长的密码/密钥', true); // 确保 32 字节密钥
[$ciphertext, $iv, $tag] = aes_gcm_encrypt('这是要加密的机密数据', $key);
// 存储时建议将三者合并:base64_encode($iv . $tag . $ciphertext)
$combined = base64_encode($iv . $tag . $ciphertext);
echo "加密后: " . $combined . PHP_EOL;
// 解密
$decoded = base64_decode($combined);
$iv = substr($decoded, 0, 12);
$tag = substr($decoded, 12, 16);
$ciphertext = substr($decoded, 28);
$plaintext = aes_gcm_decrypt($ciphertext, $iv, $tag, $key);
var_dump($plaintext); // 输出明文
?>
次选方案:AES-256-CBC + HMAC(兼容旧环境)
如果目标环境 PHP < 7.1(几乎绝迹),或需要兼容特殊库,使用 CBC 模式,但必须对密文进行 HMAC 完整性校验(加密后再签名)。
关键点:先加密(CBC),再计算 MAC(HMAC);解密时先验证 MAC,再解密。
<?php
function cbc_encrypt($plaintext, $key) {
$iv = random_bytes(16); // CBC 需要 16 字节 IV
$ciphertext_raw = openssl_encrypt(
$plaintext,
'aes-256-cbc',
$key,
OPENSSL_RAW_DATA,
$iv
);
// 生成 HMAC(签名密文 + IV)
$hmac = hash_hmac('sha256', $iv . $ciphertext_raw, $key, true);
// 合并并返回
return base64_encode($iv . $hmac . $ciphertext_raw);
}
function cbc_decrypt($data, $key) {
$decoded = base64_decode($data);
$iv = substr($decoded, 0, 16);
$hmac = substr($decoded, 16, 32);
$ciphertext = substr($decoded, 48);
// 验证 HMAC(防止篡改)
$calc_hmac = hash_hmac('sha256', $iv . $ciphertext, $key, true);
if (!hash_equals($hmac, $calc_hmac)) {
return false; // 被篡改
}
return openssl_decrypt($ciphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}
?>
密钥管理(比算法更重要)
无论选哪种算法,密钥安全是第一位的:
| 要点 | 具体建议 |
|---|---|
| 不要硬编码 | 不要将密钥写在代码里,使用环境变量或专门的密钥管理服务(如 AWS KMS, Vault)。 |
| 使用二进制密钥 | 直接用 random_bytes(32) 生成,不要用字符串密码直接加密(因为熵不足),若要密码,用 password_hash 或 hash_pbkdf2 派生。 |
| 密钥轮换 | 设计支持密钥版本号(如 k1:密文),定期更换密钥。 |
| 存储 | 将密钥文件权限设为 600,并确保 Web 服务器用户可读。 |
防坑指南(注意事项)
- IV 必须随机且唯一:永远不要重复使用同一个 IV + 同一个密钥,否则可通过 XOR 破解,使用
random_bytes()生成。 - GCM 的 Tag 必须保存:解密时忘记传 Tag 或 Tag 错了,会导致解密失败或返回
false。 - 不要用 ECB 模式:ECB 会泄露明文结构,绝对禁用。
- 不要自己设计协议:除非你是密码学专家,否则使用标准库和标准模式。
- 编码问题:
openssl_encrypt第四个参数为OPENSSL_RAW_DATA时返回二进制,存入数据库或 URL 传输前必须base64_encode。 - PHP 版本:确保
openssl扩展已启用(php -m | grep openssl)。
终极替代方案:现代加密库(libsodium)
PHP 7.2+ 内置了 sodium 扩展,它提供更安全的 crypto_secretbox(基于 XSalsa20-Poly1305),API 更简单,且完全避免误用。
<?php
// libsodium (PHP 7.2+)
$key = sodium_crypto_secretbox_keygen(); // 生成 32 字节密钥
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox('机密数据', $nonce, $key);
// 解密
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
如果你的 PHP 版本 ≥ 7.2,且不想处理 IV/TAG 拼接的细节,libsodium 是比 OpenSSL 更安全、更易用的选择。
最终决策树
你的 PHP 版本?
├── ≥ 8.0 → 如果安装 sodium 扩展 → 用 libsodium
│ → 否则用 OpenSSL AES-256-GCM ✅
├── 7.2 - 7.4 → 优先用 sodium,或 AES-256-GCM
├── 7.1 → AES-256-GCM(支持)
└── < 7.1 → 用 AES-256-CBC + HMAC(或升级 PHP,不建议在生产使用旧版)
一句话总结:用 openssl_encrypt + aes-256-gcm,密钥用 random_bytes(32) 生成,IV 随机,Tag 妥善保存,一切走标准 API。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播