PHP解密前端AES参数需确保cipher、iv、key、padding四要素完全一致:使用openssl_decrypt配合OPENSSL_RAW_DATA,iv须hex2bin转二进制,key标准化为32字节,填充统一PKCS#7。

PHP如何正确解密前端传来的AES加密参数
PHP接收前端AES加密数据,关键不在“怎么解密”,而在于两端的加解密配置必须完全一致。常见失败不是代码写错,而是模式、填充、编码、密钥处理等细节对不上。
AES加解密必须对齐的4个核心参数
前端(如JavaScript的CryptoJS或Web Crypto API)和PHP(openssl_decrypt)要能互通,以下4项必须严格一致:
-
cipher:推荐统一用AES-128-CBC或AES-256-CBC(注意PHP中对应字符串是aes-128-cbc,小写且带短横) -
iv(初始化向量):必须16字节(CBC模式),且前端与PHP使用**完全相同的原始字节值**;不能只传hex或base64后就直接用,需先还原为二进制 -
key:密钥长度必须匹配cipher(如AES-128要求16字节,AES-256要求32字节);PHP中若用字符串当key,务必用mb_convert_encoding($key, 'UTF-8', 'auto')统一编码,并用substr(hash('sha256', $key), 0, 32)等方式标准化长度 -
padding:PHP默认使用PKCS#7填充,前端也必须用同种填充;CryptoJS默认是PKCS7,但若手动指定padding: CryptoJS.pad.Pkcs7更稳妥
PHP接收并解密的典型流程(含防坑检查)
假设前端POST一个JSON:{"data": "U2FsdGVkX1+...", "iv": "abcd1234efgh5678"}(base64编码的密文 + 十六进制iv)
$_POST['data'] = 'U2FsdGVkX1+...'; // base64-encoded ciphertext
$_POST['iv'] = 'abcd1234efgh5678'; // 16-char hex string
$ciphertext = base64_decode($_POST['data']);
$iv = hex2bin($_POST['iv']); // ⚠️ 必须转为二进制!不能直接用字符串
$key = hash('sha256', 'your-secret-key', true); // 32-byte key for AES-256
$plaintext = openssl_decrypt(
$ciphertext,
'aes-256-cbc',
$key,
OPENSSL_RAW_DATA,
$iv
);
if ($plaintext === false) {
error_log('Decrypt failed: ' . openssl_error_string());
http_response_code(400);
exit;
}
常见失败原因:
立即学习“PHP免费学习笔记(深入)”;
-
openssl_decrypt返回false但没检查 —— 一定要用openssl_error_string()查具体错误 -
iv用hex2bin失败(比如传入非16字符hex)→ 解密必然失败,建议加if (strlen($_POST['iv']) !== 32) die('IV length error'); - 前端用ZeroPadding而PHP用PKCS#7 → 解密后乱码或截断
- 密文被URL编码过(如
+变空格、/被转义)→ 接收前先urldecode()再base64_decode()
为什么不要用 mcrypt_ 系列函数
mcrypt_decrypt 在PHP 7.1+ 已废弃,7.2+ 彻底移除。它默认使用ECB模式、不支持标准PKCS#7填充、IV处理不规范,且无法与现代前端库对齐。强行用只会增加调试成本。
所有新项目必须用 openssl_encrypt/openssl_decrypt,配合 OPENSSL_RAW_DATA 标志和显式IV传递——这是目前唯一稳定、可跨语言互通的路径。
最易被忽略的一点:前后端时间不同步不影响AES,但如果你在密文中嵌套了时间戳做防重放,那校验逻辑得单独做,AES本身不解决这个问题。











