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 排除 .env、config/keys.php;定期轮换密钥;生产环境禁用 display_errors 防止密钥意外输出。
安全不是功能,而是贯穿生命周期的习惯。从第一行密钥初始化开始,就该以“假设服务器已被入侵”的原则设计——这才是真正的纵深防御。
```