优先选aes-256-gcm,因其内置认证标签,可同时保障机密性与完整性;aes-256-cbc仅提供机密性,需额外加hmac防篡改,且易受填充预言攻击。

直接用 openssl_encrypt 和 openssl_decrypt,别碰 mcrypt(已废弃)或手写 XOR、base64 这类“假加密”。真要防窥探、防篡改,必须走标准对称加密流程。
选 AES-256-GCM 还是 AES-256-CBC
GCM 模式自带认证标签(authentication tag),能同时保证机密性 + 完整性,解密时自动校验是否被篡改;CBC 没这个能力,得额外加 HMAC,否则可能被填充预言攻击。但 GCM 在 PHP 7.1+ 才稳定支持,老项目若卡在 7.0 或更低,只能退到 CBC + HMAC 组合。
- AES-256-GCM:优先选,参数里必须传
$tag变量,加密后$tag要和密文一起存/传,解密时必须原样传回 - AES-256-CBC:IV 长度固定为 16 字节,必须每次随机生成,且和密文一起存储;解密前不验证 HMAC 就直接
openssl_decrypt,等于没设防 - 别用 ECB 模式——相同明文块永远输出相同密文块,一眼能看出结构,比如一张纯色图加密后还能看出轮廓
密钥和 IV 怎么生成才安全
密钥不能写死在代码里,IV 不能复用。这两点出错,加密形同虚设。
- 密钥必须用
random_bytes(32)生成(AES-256 要 32 字节),存进环境变量或 KMS,绝不能出现在 Git 历史或日志里 - IV 必须每次加密都调用
openssl_random_pseudo_bytes()或random_bytes()重新生成,长度用openssl_cipher_iv_length('AES-256-GCM')查,不是硬写 16 - IV 可以明文传输,但必须和密文绑定——比如拼成
$iv . $ciphertext . $tag(GCM)或$iv . $ciphertext(CBC),解密时再拆开
加密结果怎么存和传才不丢数据
二进制密文直接 echo、写数据库、塞 URL,大概率被截断或转义。必须编码,但别只用 base64 ——有些场景(比如做 URL 参数)base64 里的 + 和 / 会被 Web Server 误处理。
- 接口传参优先用
bin2hex():输出纯小写字母+数字,URL 安全,数据库字段类型用CHAR(64)(AES-256-CBC 密文 base64 后约 44 字符,hex 后是 64 字符) - 日志或文件存储可用
base64_encode(),但记得解密前base64_decode(),别漏这步 - 千万别对密文再做 urlencode ——它会把
=变成%3D,base64 解码失败;bin2hex结果天然不需要 urlencode
解密失败时怎么快速定位问题
常见报错如 openssl_decrypt(): IV passed is only 0 bytes long 或返回 false,基本不是算法问题,而是数据链路断了。
- 先检查 IV 长度是否匹配:CBC 要 16 字节,GCM 通常也是 12 或 16,用
strlen($iv)打印出来看 - 确认密文是否被截断:比如 MySQL 字段太短(
VARCHAR(32)存不下 AES 密文)、JSON 中没转义双引号导致解析中断 - 跨语言对接时,Java/Python 默认用 PKCS#7 填充,PHP 的
openssl_encrypt默认也是,但如果你手动用了OPENSSL_ZERO_PADDING,两边就对不上 - 别忽略错误提示:
openssl_error_string()每次解密失败后都该调一下,它会告诉你到底是密钥错、IV 错,还是 tag 验证失败
最常被跳过的一步是:加密后没验证解密能否还原。上线前至少写个单元测试,用同一组 key/iv 加密再解密,比对原始字符串。密钥管理、IV 生命周期、编码方式,这三个点只要一个松动,整个加密就不可靠。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











