最稳妥方案是使用openssl_encrypt配合AES-256-CBC,密钥须用hash('sha256', $password, true)生成32字节,IV每次随机生成16字节并拼接密文存储,严禁硬编码或固定IV。

用 openssl_encrypt 做对称加密最稳妥
PHP 自带的 openssl_encrypt 是当前最可靠的选择,比过时的 mcrypt 更安全、更易维护。它支持 AES-256-CBC 这类主流算法,且密钥和 IV 管理清晰。别用 base64_encode 或简单异或——那不算加密,只是编码或混淆。
关键点:
-
openssl_encrypt必须配对使用openssl_decrypt,不能混用其他库的解密逻辑 - 必须用随机生成的 IV(初始化向量),且每次加密都要不同;IV 可以明文附在密文前,但绝不能固定
- 密钥长度要匹配算法要求:AES-256 需要 32 字节密钥,用
hash('sha256', $password, true)生成最省事 - 推荐模式是
AES-256-CBC,不要用 ECB(会暴露重复块)
加密后怎么安全存文件?别把 IV 和密文分开管理
常见错误是把 IV 单独写进配置或数据库,结果部署时丢一个就全解不开。正确做法是把 IV 和密文拼在一起存,读取时按固定长度拆分。
示例流程:
立即学习“PHP免费学习笔记(深入)”;
- 生成 16 字节 IV:
openssl_random_pseudo_bytes(16) - 加密内容:
$ciphertext = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv) - 拼接存储:
$storage = $iv . $ciphertext(注意顺序不能反) - 解密时先截前 16 字节为 IV,剩余为密文
这样只要文件不损坏,解密逻辑就可复现,无需额外元数据。
遇到 openssl_encrypt(): Using an empty Initialization Vector 怎么办
这个警告几乎全是因传了空或 null 的 IV 导致,不是函数本身问题。检查三处:
- 是否误用
''、null或未初始化变量当 IV —— 必须用openssl_random_pseudo_bytes(16)生成 - 是否在加密前对 IV 做了 trim()、urldecode() 等操作,意外截断了二进制内容
- 是否从文件读取 IV 时用了
fgets()(会停在 \n)而不是fread($fp, 16)
顺带一提:openssl_encrypt 返回 false 时,用 openssl_error_string() 能看到具体失败原因,比猜强得多。
密码怎么变密钥?别直接拿用户密码当 AES 密钥
用户输的密码通常短、有规律,直接当 AES-256 密钥会出错或被暴力破解。必须派生:
- 用
hash('sha256', $password, true)得到 32 字节密钥(true参数返回原始二进制) - 如果需要更高强度,改用
hash_pbkdf2('sha256', $password, $salt, 100000, 32, true),其中$salt每个文件独立生成并存入文件头 - 绝对避免
md5($password)或sha1($password)—— 它们输出长度不对,且不加盐易被彩虹表攻击
真正麻烦的不是加密动作本身,而是密钥生命周期管理:密钥丢了文件就废,硬编码在代码里又等于没加密。生产环境建议用外部密钥服务或环境变量注入,别存进 Git。



















