PHP双密加密保护方案

```html PHP双密加密保护方案:安全与可控的平衡之道

PHP双密加密保护方案:安全与可控的平衡之道

在金融、政务、医疗等高敏感场景中,仅依赖单一密钥(如用户密码或系统密钥)加密数据存在明显风险:密钥泄露即全盘失守,或密钥丢失导致数据永久不可用。**双密加密(Dual-Key Encryption)** 是一种兼顾安全性与灾备能力的实用方案——它要求同时持有「用户密钥」和「服务端密钥」才能完成解密,缺一不可。 其核心思想是: ✅ **用户密钥**(如 PBKDF2 衍生自密码)掌握在用户侧,服务端不存储明文; ✅ **服务端密钥**(如 AES-256 随机密钥)由服务端安全保管(如 KMS 或环境变量); ✅ 加密时两密钥混合派生最终密钥,或分层加密(推荐:用户密钥加密数据,服务端密钥加密用户密钥)。 以下为基于 OpenSSL 的轻量级双密实现(PHP 8.1+):

🔐 示例:分层双密加解密类

<?php
class DualKeyCrypto
{
    private string $serverKey; // 服务端主密钥(建议从 env 或 KMS 获取)

    public function __construct(string $serverKey)
    {
        $this->serverKey = hash('sha256', $serverKey, true); // 确保 32 字节
    }

    public function encrypt(string $plaintext, string $userPassword): string
    {
        // Step 1: 用用户密码派生数据密钥(盐值随机)
        $userSalt = random_bytes(16);
        $dataKey = hash_pbkdf2('sha256', $userPassword, $userSalt, 100000, 32, true);

        // Step 2: 用 dataKey 加密原文(AES-256-GCM)
        $iv = random_bytes(12);
        $ciphertext = openssl_encrypt(
            $plaintext,
            'aes-256-gcm',
            $dataKey,
            OPENSSL_RAW_DATA,
            $iv,
            $authTag,
            '',
            16
        );

        // Step 3: 用 serverKey 加密 userSalt + iv + authTag(元数据)
        $meta = $userSalt . $iv . $authTag;
        $encryptedMeta = openssl_encrypt(
            $meta,
            'aes-256-ecb',
            $this->serverKey,
            OPENSSL_RAW_DATA
        );

        return base64_encode($encryptedMeta . $ciphertext);
    }

    public function decrypt(string $ciphertextB64, string $userPassword): ?string
    {
        $raw = base64_decode($ciphertextB64);
        if (strlen($raw) < 64) return null;

        // 提取加密后的元数据(前 48 字节:32(ECB密文)+16填充)与密文主体
        $encryptedMeta = substr($raw, 0, 48);
        $cipherTextBody = substr($raw, 48);

        // 解密元数据获取 userSalt/iv/authTag
        $meta = openssl_decrypt($encryptedMeta, 'aes-256-ecb', $this->serverKey, OPENSSL_RAW_DATA);
        if (!$meta || strlen($meta) !== 44) return null;

        $userSalt = substr($meta, 0, 16);
        $iv = substr($meta, 16, 12);
        $authTag = substr($meta, 28, 16);

        // 派生 dataKey 并解密
        $dataKey = hash_pbkdf2('sha256', $userPassword, $userSalt, 100000, 32, true);
        return openssl_decrypt(
            $cipherTextBody,
            'aes-256-gcm',
            $dataKey,
            OPENSSL_RAW_DATA,
            $iv,
            $authTag
        );
    }
}

// 使用示例
$crypto = new DualKeyCrypto($_ENV['SERVER_ENCRYPTION_KEY'] ?? 'your-secure-server-key');
$secret = "身份证号:11010119900307285X";
$encrypted = $crypto->encrypt($secret, 'User@2024Pass');
echo "密文:" . $encrypted . "\n";

$decrypted = $crypto->decrypt($encrypted, 'User@2024Pass');
echo "明文:" . $decrypted; // 输出原始内容
?>
⚠️ 安全提示: • 服务端密钥严禁硬编码,应通过 $_ENV 或密钥管理服务(如 AWS KMS / Aliyun KMS)注入; • 用户密码绝不参与传输或日志,PBKDF2 迭代次数建议 ≥100,000; • 生产环境需配合 HTTPS、CSP、审计日志与密钥轮换策略。
双密方案并非银弹,但它将“单点失效”风险转化为“双重授权”机制,在合规性(如等保2.0、GDPR)与用户体验间走出了一条务实路径。安全不是功能,而是持续演进的设计哲学——从双密起步,让每一份敏感数据,都拥有值得托付的守护契约。 ```