PHP 数据库敏感数据加密存储方案
在用户注册、支付、身份认证等场景中,密码、身份证号、手机号、银行卡号等属于敏感数据,绝不可明文存储于数据库。PHP 提供了成熟的安全工具链,结合现代加密实践,可构建可靠的数据保护机制。
✅ 推荐方案:AES-256-GCM 对称加密 + 密钥管理
相比过时的 mcrypt 或简单哈希(仅适用于密码),AES-256-GCM 提供机密性 + 完整性验证,且 PHP 7.1+ 原生支持 openssl_encrypt(),安全高效。
🔐 核心实现示例
<?php
// 配置:建议从环境变量或密钥管理系统加载
$encryptionKey = hex2bin(getenv('APP_ENCRYPTION_KEY') ?: '0123456789abcdef0123456789abcdef'); // 32字节 AES-256 密钥
$ivLength = openssl_cipher_iv_length('aes-256-gcm');
// ✅ 加密函数(用于写入数据库)
function encryptSensitive(string $plaintext, string $key): string
{
$iv = random_bytes($ivLength);
$tag = '';
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag,
'', // aad(可选附加认证数据,如用户ID)
16 // tag长度(推荐12–16字节)
);
if ($ciphertext === false) {
throw new RuntimeException('Encryption failed: ' . openssl_error_string());
}
return base64_encode($iv . $tag . $ciphertext); // IV + TAG + CIPHERTEXT(base64编码便于存储)
}
// ✅ 解密函数(用于读取使用)
function decryptSensitive(string $encrypted, string $key): string
{
$data = base64_decode($encrypted);
if (strlen($data) < $ivLength + 16) {
throw new RuntimeException('Invalid encrypted data length');
}
$iv = substr($data, 0, $ivLength);
$tag = substr($data, $ivLength, 16);
$ciphertext = substr($data, $ivLength + 16);
$plaintext = openssl_decrypt(
$ciphertext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
if ($plaintext === false) {
throw new RuntimeException('Decryption failed: ' . openssl_error_string());
}
return $plaintext;
}
// 🧪 使用示例
$cardNumber = '6228 4800 0000 0000 000';
$encrypted = encryptSensitive($cardNumber, $encryptionKey);
echo "加密后: {$encrypted}\n";
$decrypted = decryptSensitive($encrypted, $encryptionKey);
echo "解密后: {$decrypted}\n"; // 输出原始卡号
?>
⚠️ 关键安全提醒
- 密钥绝不硬编码:使用环境变量(如
.env)、Vault 或云 KMS 管理;禁止提交至 Git。 - 区分用途:密码应使用
password_hash()(bcrypt)单向哈希;而银行卡、证件号等需双向加解密,才用 AES。 - 字段级加密:仅加密真正敏感字段(如
user_id_card,payment_card_no),避免全表加密影响性能与查询能力。 - 审计与轮换:定期轮换密钥,并设计兼容旧密钥的解密逻辑(如添加密钥版本标识字段)。
安全不是功能,而是贯穿开发全周期的习惯。从今天起,让每一行敏感数据,都穿上加密的铠甲。
```