PHP 数据加密最佳实践
在 Web 应用中,安全地处理敏感数据(如用户密码、API 密钥、个人身份信息)是开发者的首要责任。PHP 提供了成熟、安全的加密工具,但错误使用仍可能导致严重漏洞。
✅ 优先使用 password_hash() 和 password_verify()
对密码进行哈希时,永远不要使用 md5()、sha1() 或 crypt()(无盐)。应使用 PHP 内置的现代密码哈希函数:
// ✅ 正确:使用 bcrypt(默认算法),自动加盐、自适应成本
$hash = password_hash('user_password_123', PASSWORD_DEFAULT);
// 输出类似:$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
// 验证时只需:
if (password_verify($inputPassword, $hash)) {
echo "登录成功";
}
PASSWORD_DEFAULT 会随 PHP 升级自动采用更强算法(如将来支持 Argon2),确保长期安全性。
✅ 敏感数据加密:使用 sodium_crypto_secretbox()
对于需加密存储或传输的敏感字段(如身份证号、银行卡号),推荐使用 libsodium —— PHP 7.2+ 内置、经严格审计的现代加密库:
// 生成密钥(仅一次!存于环境变量或密钥管理服务)
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
// 加密
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$message = '张三,身份证号:11010119900307251X';
$ciphertext = sodium_crypto_secretbox($message, $nonce, $key);
// 存储 $nonce . $ciphertext(nonce 可公开,但必须唯一)
$stored = base64_encode($nonce . $ciphertext);
// 解密
$decoded = base64_decode($stored);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
if ($plaintext === false) {
throw new Exception('解密失败:密钥错误或数据被篡改');
}
echo $plaintext; // 张三,身份证号:11010119900307251X
⚠️ 重要提醒:密钥(
$key)绝不可硬编码或写入代码库;应通过 $_ENV['ENCRYPTION_KEY'] 从环境变量加载,并使用 .env 文件(配合 vlucas/phpdotenv)或密钥管理服务(如 AWS KMS、HashiCorp Vault)安全分发。
❌ 避免陷阱
- 不手动实现 AES-CBC 等底层算法(易出错);
- 不重复使用 nonce(会导致密文可预测);
- 不将加密密钥与加密数据一同存储在数据库中;
- 不混淆“加密”与“编码”——
base64_encode()不是加密!
安全不是功能,而是贯穿设计、开发与运维的持续实践。从今天起,用 password_hash() 保护密码,用 sodium 保护敏感数据——让您的 PHP 应用既健壮,又值得信赖。