前端用AES加密后端解不开,哪里出问题了?
我在前端用CryptoJS做AES加密,传给后端PHP,但后端死活解密失败,密钥和模式都对上了啊。
我用的是AES-128-CBC,密钥是16位字符串,还加了PKCS7填充。前端加密代码大概是这样:
const key = CryptoJS.enc.Utf8.parse('mysecretpassword');
const iv = CryptoJS.enc.Utf8.parse('1234567890123456');
const encrypted = CryptoJS.AES.encrypt('hello world', key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(encrypted.toString());
后端说收到的密文base64解码后长度不对,是不是我哪里序列化错了?
首先最容易出问题的是密文的传输格式。CryptoJS默认返回的是一个包含多个属性的对象,直接
toString()会输出Base64格式,但可能不是后端期望的原始格式。这里需要注意两点:1. 前端加密后应该这样获取密文:
这样得到的才是纯粹的密文Base64字符串,而不是包含盐值和算法信息的复合对象。
2. 后端PHP解密时需要特别注意几点:
几个常见坑点:
- PHP的openssl默认期望的是原始二进制数据,所以要用
OPENSSL_RAW_DATA选项- 确保前端传的是纯密文,没有附加其他元数据
- IV长度必须严格16字节,和你前端设置的一致
- 两边字符编码要统一,建议都用UTF-8
如果还是有问题,可以这样调试:
1. 在前端打印出加密后的字节数组长度:
CryptoJS.enc.Base64.parse(ciphertext).toString().length2. 后端收到后同样打印base64解码后的长度
3. 比较这两个长度是否一致
最后吐槽一句,每次搞加密对接都像在拆炸弹,错一个字节就全挂了...
toString()得到的其实是CipherParams对象的特殊格式,不是纯密文。我的做法是这样修改前端代码:
然后后端PHP这样解密:
顺便吐槽下CryptoJS这个坑,我当时也折腾了好久才发现它返回的对象结构这么特别... 你试试看这样改应该就能通了!