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

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

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

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

✅ 推荐方案:AES-256-GCM + 密钥分离

相比过时的 mcrypt 或简单哈希(仅适用于密码),对称加密 + 随机 IV + 认证标签 是存储可逆敏感字段(如手机号、地址)的黄金标准。PHP 7.1+ 原生支持 openssl_encrypt(),推荐使用 AES-256-GCM 模式——它同时提供机密性与完整性校验。

🔐 安全实践要点

  • 密钥绝不硬编码:存于环境变量或专用密钥管理服务(如 HashiCorp Vault)
  • 每次加密生成唯一 IV(初始化向量),并与密文一同存储
  • 密文需包含认证标签(tag),解密时强制验证,防止篡改
  • 数据库字段类型建议VARCHAR(512)(Base64 编码后长度可控)

💻 示例代码(PHP 8.1+)

<?php
// 加密服务类(简化版)
class SecureDataCryptor
{
    private string $cipher = 'aes-256-gcm';
    private string $key;

    public function __construct(string $key)
    {
        // 密钥必须为 32 字节(AES-256)
        if (strlen($key) !== 32) {
            throw new InvalidArgumentException('AES-256 key must be exactly 32 bytes.');
        }
        $this->key = $key;
    }

    public function encrypt(string $plaintext): array
    {
        $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
        $tag = '';
        $ciphertext = openssl_encrypt(
            $plaintext,
            $this->cipher,
            $this->key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            '',
            16 // tag length
        );

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

        return [
            'ciphertext' => base64_encode($ciphertext),
            'iv'         => base64_encode($iv),
            'tag'        => base64_encode($tag),
        ];
    }

    public function decrypt(array $data): string
    {
        $ciphertext = base64_decode($data['ciphertext']);
        $iv         = base64_decode($data['iv']);
        $tag        = base64_decode($data['tag']);

        $plaintext = openssl_decrypt(
            $ciphertext,
            $this->cipher,
            $this->key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );

        if ($plaintext === false) {
            throw new RuntimeException('Decryption failed or data tampered: ' . openssl_error_string());
        }

        return $plaintext;
    }
}

// 使用示例
$key = $_ENV['APP_ENCRYPTION_KEY'] ?? '32-byte-secret-key-for-aes256!'; // ✅ 从 .env 或 secrets 注入
$cryptor = new SecureDataCryptor($key);

// 存储前加密
$phone = '13800138000';
$encrypted = $cryptor->encrypt($phone);
// → ['ciphertext'=>'...', 'iv'=>'...', 'tag'=>'...']
// 插入数据库:INSERT INTO users (encrypted_phone, phone_iv, phone_tag) VALUES (?, ?, ?)

// 读取后解密
$decryptedPhone = $cryptor->decrypt([
    'ciphertext' => $encrypted['ciphertext'],
    'iv'         => $encrypted['iv'],
    'tag'        => $encrypted['tag'],
]); // → '13800138000'
?>
⚠️ 重要提醒:密码请始终使用 password_hash() + password_verify()(bcrypt/Argon2),不可加密存储;本方案仅适用于需后续解密的业务字段(如客服查看用户手机号)。

安全无小事。加密只是纵深防御的一环——还需配合最小权限数据库账户、HTTPS 传输、定期密钥轮换及审计日志。用对工具,更要敬畏风险。

```