PHP 数据加密最佳实践
在 Web 应用中,敏感数据(如用户密码、API 密钥、个人身份信息)必须安全存储与传输。PHP 提供了成熟、标准化的加密工具,但错误使用仍可能导致严重风险。以下是经过验证的最佳实践。
✅ 1. 密码哈希:永远使用 password_hash()
切勿手动实现 MD5、SHA1 或简单 salted hash —— 它们已不安全且易被暴力破解。
// ✅ 正确:使用 bcrypt(PHP 7.0+ 默认算法)
$hash = password_hash('user_password_123', PASSWORD_ARGON2ID);
// 或兼容性更强的 bcrypt(推荐用于旧环境)
$hash = password_hash('user_password_123', PASSWORD_BCRYPT, ['cost' => 12]);
// ✅ 验证时使用 password_verify()
if (password_verify($input, $stored_hash)) {
echo "登录成功";
}
关键点:无需管理 salt;算法自动升级;验证函数恒定时间比较,防时序攻击。
✅ 2. 敏感数据加密:使用 sodium_crypto_secretbox()
对于需「可逆加密」的场景(如加密数据库中的邮箱、手机号),优先选用 Libsodium(PHP 7.2+ 内置)。
// 生成并安全存储 256 位密钥(一次生成,长期复用)
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
// 加密
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$encrypted = sodium_crypto_secretbox('john@example.com', $nonce, $key);
// 解密
$decrypted = sodium_crypto_secretbox_open($encrypted, $nonce, $key);
echo $decrypted; // john@example.com
优势:AEAD 模式(认证加密),自动防篡改;无需自行处理 IV/nonce 管理;比 OpenSSL 更难误用。
⚠️ 避免陷阱
❌ 不要:
• 使用
• 用
• 将密钥硬编码在代码中 —— 使用环境变量或密钥管理服务(如 HashiCorp Vault)
• 对同一明文重复使用相同 nonce(Libsodium 中 nonce 必须唯一)
• 使用
mcrypt_*()(已废弃且不安全)• 用
openssl_encrypt() 而不指定 AEAD 模式(如 AES-GCM)或手动验证 HMAC• 将密钥硬编码在代码中 —— 使用环境变量或密钥管理服务(如 HashiCorp Vault)
• 对同一明文重复使用相同 nonce(Libsodium 中 nonce 必须唯一)
🔐 补充建议
- 密钥管理:生产环境密钥应通过
getenv('ENCRYPTION_KEY')读取,并由部署系统注入。 - HTTPS 强制:所有含敏感数据的请求必须走 HTTPS,防止传输层泄露。
- 最小权限原则:数据库用户仅授予必要字段的读写权限,避免全表 SELECT 泄露加密数据。
安全不是功能,而是持续过程。定期更新 PHP 版本、审计加密逻辑、启用 sodium 扩展,才能真正守护用户信任。