PHP 数据库敏感数据加密存储方案

```html PHP 数据库敏感数据加密存储方案

PHP 数据库敏感数据加密存储方案

在用户注册、支付、身份认证等场景中,密码、身份证号、手机号、银行卡号等属于敏感数据,绝不可明文存储于数据库。PHP 提供了成熟的安全工具链,结合现代加密实践,可构建可靠的数据保护机制。

✅ 推荐方案:AES-256-GCM 对称加密 + 密钥管理

相比过时的 mcrypt 或简单哈希(仅适用于密码),AES-256-GCM 具备机密性与完整性验证,且 PHP 7.1+ 原生支持 openssl_encrypt(),无需扩展依赖。

🔐 示例:加密/解密手机号

<?php
// 配置:从环境变量或配置中心加载密钥(切勿硬编码!)
$key = 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长度(GCM推荐12–16字节)
    );
    
    if ($ciphertext === false) {
        throw new RuntimeException('Encryption failed: ' . openssl_error_string());
    }
    
    return base64_encode($iv . $tag . $ciphertext); // 拼接 IV+TAG+CIPHER,Base64 安全存储
}

// ✅ 解密函数(用于读取后展示/校验)
function decryptSensitive(string $encrypted, string $key): string
{
    $data = base64_decode($encrypted);
    $iv = mb_substr($data, 0, $ivLength, '8bit');
    $tag = mb_substr($data, $ivLength, 16, '8bit');
    $ciphertext = mb_substr($data, $ivLength + 16, null, '8bit');
    
    $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;
}

// 使用示例
$phone = '13812345678';
$encryptedPhone = encryptSensitive($phone, $key);
echo "加密后: {$encryptedPhone}\n"; // 存入数据库 user.phone_encrypted 字段

$decryptedPhone = decryptSensitive($encryptedPhone, $key);
echo "解密后: {$decryptedPhone}\n"; // 输出:13812345678
?>
⚠️ 重要安全提醒:
• 密钥($key)必须通过 getenv() 从环境变量或密钥管理服务(如 AWS KMS、Vault)加载,严禁写死在代码中;
• IV 和 TAG 必须随密文一同持久化(本例已合并 Base64),且每次加密使用全新随机 IV;
• 敏感字段命名建议加 `_encrypted` 后缀(如 id_card_encrypted),避免混淆;
• 密码类字段仍应使用 password_hash() + password_verify()(bcrypt),不可用对称加密替代哈希

结语:加密是纵深防御的一环。配合 PDO 参数化查询防注入、最小权限数据库账户、HTTPS 传输、定期密钥轮换,才能真正筑牢数据安全防线。安全无小事,每一步都值得敬畏。

```