PHP 数据库敏感数据加密存储方案
在用户注册、支付、身份认证等场景中,密码、手机号、身份证号、银行卡号等属于敏感数据,绝不能以明文形式存入数据库。PHP 提供了成熟的安全加密机制,本文介绍一种符合最佳实践的端到端加密方案。
✅ 推荐方案:AES-256-GCM 对称加密 + 密钥分离管理
相比哈希(仅适用于密码),AES-GCM 支持可逆加密,兼顾机密性与完整性验证(防篡改),且性能优异。关键原则:
- 使用
openssl_encrypt()/openssl_decrypt()(PHP 7.1+) - 密钥(
$key)绝不硬编码,应通过环境变量或密钥管理服务(如 AWS KMS)注入 - 每次加密生成唯一随机 IV(初始化向量),并随密文一并存储
🔐 加密/解密工具类示例
<?php
class SecureDataCryptor
{
private const CIPHER = 'aes-256-gcm';
private const KEY_LENGTH = 32; // 256 bits
public static function encrypt(string $plaintext, string $key): string
{
$iv = random_bytes(openssl_cipher_iv_length(self::CIPHER));
$tag = '';
$ciphertext = openssl_encrypt(
$plaintext,
self::CIPHER,
$key,
OPENSSL_RAW_DATA,
$iv,
$tag,
'', // aad (optional)
16 // tag length
);
if ($ciphertext === false) {
throw new RuntimeException('Encryption failed: ' . openssl_error_string());
}
return base64_encode($iv . $tag . $ciphertext);
}
public static function decrypt(string $encrypted, string $key): string
{
$data = base64_decode($encrypted);
$ivLen = openssl_cipher_iv_length(self::CIPHER);
$tagLen = 16;
$iv = substr($data, 0, $ivLen);
$tag = substr($data, $ivLen, $tagLen);
$ciphertext = substr($data, $ivLen + $tagLen);
$plaintext = openssl_decrypt(
$ciphertext,
self::CIPHER,
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
if ($plaintext === false) {
throw new RuntimeException('Decryption failed: ' . openssl_error_string());
}
return $plaintext;
}
}
// 使用示例(生产环境请从 $_ENV['ENCRYPTION_KEY'] 获取)
$key = hash_pbkdf2('sha256', $_ENV['APP_SECRET'] ?? 'your-app-secret', 'data-encryption-salt', 100000, 32, true);
$phone = '138****1234';
$encryptedPhone = SecureDataCryptor::encrypt($phone, $key);
echo "密文: {$encryptedPhone}\n";
echo "原文: " . SecureDataCryptor::decrypt($encryptedPhone, $key);
?>
⚠️ 重要提醒:
• 密码字段请始终使用
• 敏感字段加密后需在数据库中使用
• 建议对加密字段添加数据库注释,如
• 密码字段请始终使用
password_hash() + password_verify()(不可逆哈希);• 敏感字段加密后需在数据库中使用
TEXT 或 JSON 类型存储(长度 ≥ 512 字符);• 建议对加密字段添加数据库注释,如
/* ENCRYPTED_VIA_AES256GCM */,便于团队协作。
安全无小事。加密只是纵深防御的一环——还需配合 HTTPS 传输、最小权限数据库账号、定期密钥轮换及审计日志。让每一份用户数据,都值得被郑重守护。
```