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

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

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

在用户注册、支付、身份认证等场景中,密码、手机号、身份证号、银行卡号等属于敏感数据,绝不可明文存储于数据库。PHP 提供了成熟的安全工具链,本文介绍一种符合 OWASP 和 GDPR 原则的端到端加密实践方案。

✅ 核心原则

  • 加密而非哈希:对需可逆读取的字段(如手机号)使用 AES-256-GCM 加密;
  • 密钥分离:主密钥(KEK)存于环境变量或密钥管理服务(KMS),不与代码/数据库共存;
  • 每字段独立 IV:每次加密生成唯一随机初始化向量(IV),避免相同明文产生相同密文;
  • 认证加密:选用 GCM 模式,同时保障机密性与完整性。

🔐 示例:加密存储用户手机号

<?php
// config.php —— 密钥应从环境变量加载(如 .env)
$encryptionKey = base64_decode($_ENV['APP_ENCRYPTION_KEY'] ?? 'your-32-byte-base64-key-here==');

function encryptField(string $plaintext, string $key): string
{
    $iv = random_bytes(12); // GCM 推荐 12 字节 IV
    $tag = '';
    $ciphertext = openssl_encrypt(
        $plaintext,
        'aes-256-gcm',
        $key,
        OPENSSL_RAW_DATA,
        $iv,
        $tag,
        '', // aad (可选附加认证数据)
        16 // tag length
    );

    if ($ciphertext === false) {
        throw new RuntimeException('Encryption failed: ' . openssl_error_string());
    }

    return base64_encode($iv . $tag . $ciphertext);
}

function decryptField(string $encrypted, string $key): string
{
    $data = base64_decode($encrypted);
    $iv = substr($data, 0, 12);
    $tag = substr($data, 12, 16);
    $ciphertext = substr($data, 28);

    $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 = '+8613800138000';
$encryptedPhone = encryptField($phone, $encryptionKey);
// 存入数据库:INSERT INTO users (encrypted_phone) VALUES (?)

$decryptedPhone = decryptField($encryptedPhone, $encryptionKey);
echo $decryptedPhone; // → '+8613800138000'
?>

⚠️ 重要提醒

不要自行实现密码存储! 对密码请始终使用 password_hash() + password_verify()(基于 Argon2i 或 bcrypt)。本文方案仅适用于需要解密的业务字段(如脱敏展示、短信验证回显等)。

最后,建议结合数据库列级加密(如 MySQL 8.0+ 的 AES_ENCRYPT())、应用层密钥轮换机制及审计日志,构建纵深防御体系。安全不是功能,而是贯穿设计、开发与运维的持续实践。

```