PHP 加密密钥管理与安全存储
在 PHP 应用中,正确管理加密密钥是保障数据安全的核心环节。密钥一旦泄露或硬编码,再强的加密算法也形同虚设。
❌ 常见错误实践
以下方式绝对禁止:
define('ENCRYPTION_KEY', 'my-secret-123!');(硬编码于代码中)- 将密钥写入
config.php并提交至 Git 仓库 - 使用弱随机源(如
rand()或时间戳)生成密钥
✅ 推荐安全实践
1. 使用环境变量隔离密钥
通过系统环境变量加载密钥,避免代码污染:
# Linux/macOS:启动前设置
export APP_ENCRYPTION_KEY="base64:qUJv...ZmYzI="
# PHP 中读取(推荐使用 vlucas/phpdotenv 处理 .env)
$key = $_ENV['APP_ENCRYPTION_KEY'] ?? null;
if (!$key || !str_starts_with($key, 'base64:')) {
throw new RuntimeException('Invalid encryption key');
}
$rawKey = base64_decode(substr($key, 7));
2. 使用 Sodium 扩展(PHP 7.2+ 内置)
Sodium 是现代、安全、易用的加密库,无需第三方依赖:
<?php
// 生成并安全存储密钥(仅执行一次!)
$key = sodium_crypto_secretbox_keygen();
file_put_contents('/etc/app/secret.key', $key, LOCK_EX); // 权限:600
chmod('/etc/app/secret.key', 0600);
// 运行时加载(确保 Web 服务器有读权限)
$key = file_get_contents('/etc/app/secret.key');
if ($key === false) {
throw new RuntimeException('Failed to load encryption key');
}
// 加密示例
$message = 'Sensitive user data';
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($message, $nonce, $key);
// 存储 nonce + ciphertext(nonce 可公开)
$storage = base64_encode($nonce . $ciphertext);
?>
3. 密钥轮换与版本控制
为支持密钥更新,建议添加版本标识:
$encrypted = [
'v' => 2, // 密钥版本
'n' => base64_encode($nonce),
'c' => base64_encode($ciphertext)
];
// 解密时根据 'v' 选择对应密钥文件
⚠️ 重要提醒:
• 永远不要将密钥存入数据库或 Web 可访问目录;
• 生产环境禁用
display_errors,防止密钥意外输出;
• 定期审计密钥权限:ls -l /etc/app/secret.key 应显示 -rw-------。
安全不是功能,而是持续实践。从今天起,让每一把密钥都住在它该住的地方——受控、隔离、可审计。
```