PHP双密加密保护方案

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

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

在金融、政务、医疗等高敏感场景中,仅依赖单一密钥(如用户密码或系统密钥)加密数据存在明显风险:密钥泄露即全盘失守,或管理员权限过大导致“内部越权”。为此,“**双密加密**”(Dual-Key Encryption)应运而生——它要求**用户密钥 + 系统密钥**协同参与加解密,实现责任分离与最小权限原则。 双密并非指“两次加密”,而是采用**密钥派生+分层封装**机制: ✅ 用户密码经 PBKDF2 派生出 `userKey`(仅客户端/可信环境掌握) ✅ 系统主密钥 `masterKey` 安全存储于配置中心或 HSM ✅ 加密时:用 `userKey` 加密明文 → 得密文;再用 `masterKey` 加密 `userKey` → 得密钥信封 ✅ 解密时:先用 `masterKey` 解封获得 `userKey`,再用其解密数据 该方案兼顾安全性(无 `userKey` 则无法解密)、可审计性(密钥使用留痕),且支持密钥轮换(仅重封 `userKey` 即可)。

PHP 实现示例(基于 OpenSSL)

<?php
class DualKeyCrypto {
    private const KEY_DERIVE_ITERATIONS = 100000;
    private const CIPHER = 'AES-256-GCM';

    public static function encrypt(string $plaintext, string $userPassword, string $masterKey): array {
        // 1. 派生用户密钥(加盐)
        $salt = random_bytes(16);
        $userKey = hash_pbkdf2('sha256', $userPassword, $salt, self::KEY_DERIVE_ITERATIONS, 32, true);

        // 2. 用 userKey 加密数据
        $iv = random_bytes(12); // GCM IV 长度为 12 字节
        $tag = '';
        $ciphertext = openssl_encrypt(
            $plaintext,
            self::CIPHER,
            $userKey,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            '', // aad
            16 // tag length
        );

        if ($ciphertext === false) throw new RuntimeException('Encryption failed');

        // 3. 用 masterKey 加密 userKey(密钥信封)
        $envIv = random_bytes(16);
        $envelope = openssl_encrypt(
            $userKey,
            'AES-256-CBC',
            $masterKey,
            OPENSSL_RAW_DATA,
            $envIv
        );

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

    public static function decrypt(array $payload, string $userPassword, string $masterKey): string {
        // 1. 从 salt 派生 userKey
        $salt = base64_decode($payload['salt']);
        $userKey = hash_pbkdf2('sha256', $userPassword, $salt, self::KEY_DERIVE_ITERATIONS, 32, true);

        // 2. 用 masterKey 解封 userKey
        $envIv = base64_decode($payload['env_iv']);
        $envelope = base64_decode($payload['envelope']);
        $unwrappedKey = openssl_decrypt(
            $envelope,
            'AES-256-CBC',
            $masterKey,
            OPENSSL_RAW_DATA,
            $envIv
        );

        if ($unwrappedKey !== $userKey) {
            throw new RuntimeException('Key verification failed — possible tampering or password mismatch');
        }

        // 3. 用 userKey 解密数据
        $iv = base64_decode($payload['iv']);
        $tag = base64_decode($payload['tag']);
        $ciphertext = base64_decode($payload['ciphertext']);

        $plaintext = openssl_decrypt(
            $ciphertext,
            self::CIPHER,
            $userKey,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );

        if ($plaintext === false) throw new RuntimeException('Decryption failed');
        return $plaintext;
    }
}

// 使用示例
$masterKey = 'your-32-byte-system-master-key!'; // 应从 env 或 vault 获取
$userPass = 'MyS3cur3P@ss';
$data = '身份证号:11010119900307285X;健康档案ID:HJ2024-7891';

try {
    $encrypted = DualKeyCrypto::encrypt($data, $userPass, $masterKey);
    echo "✅ 加密成功\n";
    print_r($encrypted);

    $decrypted = DualKeyCrypto::decrypt($encrypted, $userPass, $masterKey);
    echo "\n✅ 解密验证:".($decrypted === $data ? "一致" : "不一致")."\n";
} catch (Exception $e) {
    echo "❌ 错误:".$e->getMessage();
}
?>
安全提示:$masterKey 必须通过环境变量或密钥管理服务(如 HashiCorp Vault)注入,严禁硬编码; • 用户密码不得明文传输,前端需做轻量哈希(如 Argon2)预处理; • 生产环境建议结合 OpenSSL FIPS 模式及审计日志记录密钥使用行为。
双密方案不是银弹,但为 PHP 应用提供了符合等保2.0与GDPR“默认安全”原则的实用路径。当安全不再只是“加一层锁”,而是“设计两把钥匙”,数据主权才真正回归用户与系统共建的信任框架。 ```