PHP 加密安全常见漏洞与防护
加密不是“加了就安全”,错误的实现反而会引入严重风险。以下是 PHP 开发中高频出现的加密安全陷阱及正确实践。
❌ 漏洞一:使用过时/不安全的哈希算法
md5()、sha1() 已被证实易受碰撞攻击,且无盐值(salt)导致彩虹表可批量破解。
危险示例:
$password_hash = md5($_POST['password']); // ❌ 绝对禁止
✅ 正确做法:使用
password_hash()(PHP 5.5+)
// 自动加盐 + 使用 bcrypt(推荐)或 argon2id
$hash = password_hash($_POST['password'], PASSWORD_ARGON2ID);
// 验证时无需关心盐值和算法细节
if (password_verify($_POST['password'], $hash)) {
echo "登录成功";
}
❌ 漏洞二:手动实现加密/解密逻辑
自行拼接 IV、硬编码密钥、忽略认证加密(AEAD),极易导致 CBC 填充攻击或密文篡改。
危险示例(AES-CBC 无认证):
$key = 'hardcoded_key_16'; // ❌ 密钥硬编码 + 无认证
$iv = openssl_random_pseudo_bytes(16);
$cipher = openssl_encrypt($data, 'AES-128-CBC', $key, 0, $iv); // ❌ 易受 Padding Oracle 攻击
✅ 推荐:使用
sodium_crypto_secretbox()(PHP 7.2+)
$key = sodium_crypto_secretbox_keygen(); // 安全生成密钥
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$encrypted = sodium_crypto_secretbox($data, $nonce, $key);
// 验证+解密一步完成,失败直接返回 false
$decrypted = sodium_crypto_secretbox_open($encrypted, $nonce, $key);
❌ 漏洞三:混淆 ≠ 加密
base64_encode()、str_rot13() 等仅是编码/变换,无密钥、无熵,完全不具备保密性。
典型误用:
$token = base64_encode("user_id=123&role=admin"); // ❌ 可瞬间解码
✅ 正确方案:敏感数据应存储于服务端 Session;若需客户端传递,使用 带签名的 JWT(如 firebase/php-jwt)或短期有效、服务端校验的一次性 Token。
📌 关键原则总结
- 哈希密码 → 用
password_hash()/password_verify() - 加密敏感数据 → 优先选
libsodium(sodium_crypto_secretbox或sodium_crypto_aead) - 绝不硬编码密钥 → 使用环境变量或密钥管理服务(如 HashiCorp Vault)
- 避免自研密码学逻辑 —— 即使是“简单替换”也违背 Kerckhoffs 原则
安全不是功能开关,而是贯穿设计、开发与运维的持续实践。从今天起,让每一行加密代码都经得起专业审视。
```