PHP 加密密钥管理与安全存储

```html PHP 加密密钥管理与安全存储

PHP 加密密钥管理与安全存储

在 PHP 应用中,加密(如 AES、RSA)是保护敏感数据的关键手段。但密钥本身的安全性往往比算法更重要——密钥泄露即等于数据裸奔。

❌ 常见错误做法

  • 硬编码密钥到源码中(define('ENCRYPTION_KEY', 'my-secret-123...')
  • 将密钥存于 Web 可访问目录下的配置文件(如 /config/keys.php
  • 使用弱随机源生成密钥(如 md5(time().rand())

✅ 推荐实践方案

1. 使用环境变量 + .env(推荐开发/测试)

借助 vlucas/phpdotenv 安装后:

# .env 文件(确保不在 Web 根目录下!)
APP_ENCRYPTION_KEY=base64:YzVjNzIwZTUtZmQyYS00YjE5LWIxMjMtOTkxYjJiMzU1MDJl

PHP 中安全读取:

<?php
require_once 'vendor/autoload.php';
Dotenv\Dotenv::createImmutable(__DIR__)->load();

// 安全解码并验证长度(AES-256 需 32 字节)
$key = base64_decode($_ENV['APP_ENCRYPTION_KEY'] ?? '');
if (strlen($key) !== 32) {
    throw new RuntimeException('Invalid encryption key length');
}

// 使用 OpenSSL 加密示例
$plaintext = '用户身份证号:11010119900307271X';
$ivlen = openssl_cipher_iv_length($cipher = 'AES-256-CBC');
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext = openssl_encrypt($plaintext, $cipher, $key, 0, $iv);

echo base64_encode($iv . $ciphertext); // 存储 IV + 密文(IV 可公开)
?>

2. 生产环境:操作系统级密钥管理

Linux 下可结合 systemd 环境或专用密钥服务:

# 启动服务时注入(systemd unit)
EnvironmentFile=/etc/secrets/php-app.env

# 或使用 HashiCorp Vault(需 SDK)
use HashiCorp\Vault\Client;
$client = new Client(['token' => $_SERVER['VAULT_TOKEN']]);
$keyData = $client->secrets()->kv2()->get('php/app/encryption-key');
$key = base64_decode($keyData['data']['key']);

3. 密钥轮换支持(重要!)

避免单点失效,设计版本化密钥:

$keys = [
    'v1' => base64_decode($_ENV['KEY_V1'] ?? ''),
    'v2' => base64_decode($_ENV['KEY_V2'] ?? ''),
];
$activeKeyVersion = 'v2';

// 加密用最新版,解密兼容多版本
function decrypt(string $ciphertext, array $keys): string {
    $data = base64_decode($ciphertext);
    $iv = substr($data, 0, 16);
    $ciphertextRaw = substr($data, 16);
    
    foreach ($keys as $version => $key) {
        $result = openssl_decrypt($ciphertextRaw, 'AES-256-CBC', $key, 0, $iv);
        if ($result !== false) return $result;
    }
    throw new Exception('Decryption failed for all keys');
}
⚠️ 关键提醒:永远不要将密钥提交至 Git;使用 .gitignore 排除 .envconfig/keys.php;定期轮换密钥;生产环境禁用 display_errors 防止密钥意外输出。

安全不是功能,而是贯穿生命周期的习惯。从第一行密钥初始化开始,就该以“假设服务器已被入侵”的原则设计——这才是真正的纵深防御。

```