PHP 加密服务生产环境部署方案
在金融、支付、用户隐私等高安全场景中,PHP 应用需提供稳定、可审计、防篡改的加密能力。本文介绍一套兼顾安全性、性能与可维护性的生产级加密服务部署方案。核心原则
- 密钥分离:加密密钥(KEK)与数据密钥(DEK)分层管理,密钥不硬编码
- 算法合规:优先使用
openssl_encrypt()+ AES-256-GCM(认证加密) - 密钥轮换:支持多版本密钥并存,平滑迁移旧密文
- 环境隔离:开发/测试/生产使用独立密钥源(如 Vault 或环境变量)
推荐实现:AES-256-GCM 封装类
<?php
class SecureCryptoService
{
private const KEY_VERSION = 'v1';
private string $encryptionKey;
public function __construct(string $key)
{
if (mb_strlen($key, '8bit') !== 32) {
throw new InvalidArgumentException('AES-256 key must be 32 bytes');
}
$this->encryptionKey = $key;
}
public function encrypt(string $plaintext): string
{
$iv = random_bytes(12); // GCM recommended IV length: 12 bytes
$tag = '';
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$this->encryptionKey,
OPENSSL_RAW_DATA,
$iv,
$tag,
'', // aad (optional)
16 // tag length
);
if ($ciphertext === false) {
throw new RuntimeException('Encryption failed: ' . openssl_error_string());
}
return base64_encode(self::KEY_VERSION . ':' . $iv . $tag . $ciphertext);
}
public function decrypt(string $encrypted): string
{
$decoded = base64_decode($encrypted);
if (substr($decoded, 0, 3) !== 'v1:') {
throw new RuntimeException('Unsupported key version');
}
$data = substr($decoded, 3);
$iv = substr($data, 0, 12);
$tag = substr($data, 12, 16);
$ciphertext = substr($data, 28);
$plaintext = openssl_decrypt(
$ciphertext,
'aes-256-gcm',
$this->encryptionKey,
OPENSSL_RAW_DATA,
$iv,
$tag
);
if ($plaintext === false) {
throw new RuntimeException('Decryption failed: ' . openssl_error_string());
}
return $plaintext;
}
}
// 使用示例(生产环境应从 Vault 或加密配置中心加载密钥)
$secretKey = $_ENV['APP_ENCRYPTION_KEY'] ?? throw new RuntimeException('Missing APP_ENCRYPTION_KEY');
$crypto = new SecureCryptoService($secretKey);
$encrypted = $crypto->encrypt('user_token_abc123');
echo "Encrypted: {$encrypted}\n";
echo "Decrypted: " . $crypto->decrypt($encrypted) . "\n";
?>
✅ 生产就绪提示:将
APP_ENCRYPTION_KEY 存入 HashiCorp Vault、AWS KMS 或 Kubernetes Secrets,并通过 init container 注入环境变量;禁用 phpinfo() 和错误回显,避免密钥泄露。
⚠️ 切勿使用:
mcrypt(已废弃)、md5()/sha1()(非加密哈希)、未加盐的 password_hash() 用于敏感字段加密(应仅用于密码存储)。