PHP使用sodium_crypto_secretbox加密配置密钥,解密密钥存储成难题?
问题背景与疑问
我在PHP 8.2的Web应用里,把密钥存放在根目录外的/private文件夹下的.ini文件中,现在被要求加密这个.ini文件里的数据,理由是直接读取密钥不够安全。
原读取代码:
$cfg = parse_ini_file('../../private/config.ini'); $my_secret_key_123 = $cfg['secret_key_123']; $my_secret_key_345 = $cfg['secret_key_345'];
我原本打算用sodium扩展加密数据,加密代码如下:
$key = sodium_crypto_secretbox_keygen(); $nonce = random_bytes( SODIUM_CRYPTO_SECRETBOX_NONCEBYTES ); $encrypted_result = sodium_crypto_secretbox( 'secret_key_123', $nonce, $key ); $encoded_secret_key_123 = base64_encode( $nonce . $encrypted_result );
但解密时需要用到加密生成的$key和$nonce,解密代码如下:
$decoded = base64_decode($encoded_secret_key_123, false); $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit'); $encrypted_result = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit'); $plaintext = sodium_crypto_secretbox_open($encrypted_result, $nonce, $key);
现在有两个疑问:
- 如何安全存储
sodium_crypto_secretbox_keygen生成的密钥? - 这种加密方式是不是过度设计?改用简单的base64编码行不行?
解答
关于加密是否过度设计
首先明确:base64编码不是加密,只是二进制数据的文本化转换,任何人拿到base64内容都能轻松解码出原文,完全起不到保密作用,绝对不能用它替代加密。
你的场景里,如果服务器被攻击者入侵并获取到/private/config.ini的访问权限,直接存明文密钥确实风险很高,用sodium加密是合理的,不属于过度设计——但前提是你能安全存储加密用的密钥。
如何安全存储sodium加密密钥
核心原则是把加密密钥和加密后的配置文件分开存放,避免攻击者同时拿到两者,具体可行方案有:
- 利用服务器环境变量:把
sodium_crypto_secretbox_keygen()生成的密钥存在服务器的环境变量中(比如Nginx配置、系统环境变量文件、PHP-FPM配置),PHP通过getenv('YOUR_ENCRYPTION_KEY')读取。这种方式下,即使攻击者拿到.ini文件,没有环境变量里的密钥也无法解密。 - 使用云服务商密钥管理服务:如果是云服务器,可将加密密钥存放在AWS KMS、阿里云密钥管理服务这类专门的密钥管理平台,PHP通过API调用获取密钥(需做好权限控制,确保只有你的应用能访问)。
- 本地硬件加密模块:如果是物理服务器,可将密钥存放在TPM(可信平台模块)这类硬件中,通过专门接口读取,安全性极高,但成本和复杂度也相对更高。
额外注意:
- 不要把加密密钥存放在代码仓库、应用目录下的任何文件里,也不要硬编码在PHP代码中。
- 生成的密钥务必做好备份,一旦丢失,加密后的配置数据将彻底无法解密。
内容的提问来源于stack exchange,提问作者ToddN
相关产品推荐
相关产品推荐

