PHP 数据加密最佳实践
在 Web 应用中,敏感数据(如用户密码、API 密钥、个人身份信息)必须安全存储与传输。PHP 提供了成熟、可靠的加密工具,但错误使用仍可能导致严重安全隐患。
✅ 首选:使用 password_hash() 和 password_verify()
密码绝不可使用 MD5、SHA1 或简单 base64 编码——它们不是加密,而是单向哈希且无盐,极易被彩虹表破解。
// ✅ 正确:使用 bcrypt(PHP 5.5+ 原生支持)
$password = "user_secret_123";
$hash = password_hash($password, PASSWORD_ARGON2ID); // 推荐 Argon2id(PHP 7.2+)
// 或兼容性更强的:PASSWORD_BCRYPT
// 验证时无需关心算法细节
if (password_verify($inputPassword, $storedHash)) {
echo "登录成功";
}
优势:自动加盐、自适应计算强度、算法升级后仍可验证旧哈希。
🔐 敏感字段加密:使用 sodium_crypto_secretbox()
对数据库中需「可逆加密」的字段(如邮箱、身份证号),推荐 PHP 内置的 libsodium(PHP 7.2+ 默认启用):
// 生成密钥(一次生成,安全保存于环境变量中!)
$key = sodium_crypto_secretbox_keygen();
// 加密
$message = "zhangsan@example.com";
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($message, $nonce, $key);
// 解密
$decrypted = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
echo $decrypted; // → "zhangsan@example.com"
注意:密钥 绝不硬编码,应通过 $_ENV['ENCRYPTION_KEY'] 从环境变量加载,并确保密钥长度为 32 字节。
⚠️ 绝对避免的陷阱
× 错误示例:
•
• 自实现 AES-CBC 而未正确处理 IV/填充/认证
• 使用
• 将密钥写死在代码或 Git 仓库中
•
md5($password) 或 sha1($password . $salt)• 自实现 AES-CBC 而未正确处理 IV/填充/认证
• 使用
mcrypt_*(已废弃且不安全)• 将密钥写死在代码或 Git 仓库中
📌 最佳实践清单
- 密码:始终用
password_hash()+password_verify() - 敏感字段加密:优先选用
sodium_crypto_secretbox(AEAD 认证加密) - 密钥管理:使用环境变量 + 严格文件权限(如
chmod 600 .env) - 传输层:强制 HTTPS(TLS 1.2+),禁用明文 HTTP
- 定期轮换:对长期有效的加密密钥制定轮换策略
安全不是功能,而是贯穿开发全周期的习惯。选择现代、经过审计的原生函数,比任何“自研加密”都更可靠。
```