前端解密后端数据需严格匹配算法、密钥、iv、填充和编码;依赖web crypto api或cryptojs等库,须先确认后端具体方案(如aes-128-cbc)、密钥来源、iv传递方式、base64/hex编码及pkcs#7等填充。

前端解密后端返回的加密数据,核心在于前后端使用**完全一致的加密算法、密钥、IV(初始化向量)、填充方式和编码格式**。JavaScript 本身不内置对称/非对称解密能力,需依赖 Web Crypto API(现代浏览器)或成熟第三方库(如 CryptoJS、forge),且必须与后端严格对齐参数。
确认后端使用的具体加密方案
这是最关键的一步。不能凭猜测写解密逻辑。需明确以下信息:
- 算法类型:AES-128-CBC、AES-256-GCM、RSA-OAEP、SM4-CBC 等(注意国密 SM2/SM4 需额外支持)
- 密钥来源:是固定密钥?还是通过登录后动态协商(如 RSA 加密传输 AES 密钥)?或是从 localStorage / cookie 读取?
- IV 或 nonce:是否随数据一起返回(常见于 CBC/GCM 模式)?长度是否正确(如 AES-CBC 要求 16 字节)?
- 数据编码:后端返回的是 base64?hex?还是直接二进制流(需用 Uint8Array 处理)?
- 填充方式:PKCS#7?ZeroPadding?GCM 无需填充。
使用 Web Crypto API 解密(推荐,原生安全)
适用于现代浏览器(Chrome 80+、Firefox 69+、Edge 79+)。以 AES-CBC 为例:
假设后端返回 JSON:{"data": "base64密文", "iv": "base64 IV"}
async function decryptAES(dataB64, ivB64, keyStr) {
// 1. 将 base64 转为 Uint8Array
const ciphertext = base64ToArrayBuffer(dataB64);
const iv = base64ToArrayBuffer(ivB64);
// 2. 导入密钥(注意:keyStr 必须是原始密钥字节,不是字符串直接转!)
// 若后端用 password派生密钥(如 PBKDF2),此处需先执行 deriveKey
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(keyStr), // ⚠️仅当 keyStr 是原始密钥字节时才这样用
{ name: 'AES-CBC' },
false,
['decrypt']
);
// 3. 执行解密
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-CBC', iv },
key,
ciphertext
);
// 4. 转为字符串(假设 UTF-8)
return new TextDecoder().decode(decrypted);
}
function base64ToArrayBuffer(base64) {
const bin = atob(base64);
const len = bin.length;
const buf = new ArrayBuffer(len);
const view = new Uint8Array(buf);
for (let i = 0; i
<h3>使用 CryptoJS(兼容旧浏览器,但注意安全风险)</h3>
<p>若需支持 IE 或老版本浏览器,可用 CryptoJS,但需确保版本与后端一致(如 CryptoJS 3.1.2 对应某些 Java 后端实现):</p>
<pre class="brush:javascript;toolbar:false;">// 注意:CryptoJS 默认使用 OpenSSL 格式密钥派生(EVP_BytesToKey),若后端未用此方式,必须手动对齐
const CryptoJS = require('crypto-js');
function decryptWithCryptoJS(ciphertextB64, keyStr, ivB64) {
const ciphertext = CryptoJS.enc.Base64.parse(ciphertextB64);
const iv = CryptoJS.enc.Base64.parse(ivB64);
const key = CryptoJS.enc.Utf8.parse(keyStr); // ⚠️仅当 keyStr 是原始 16/24/32 字节密钥时才正确
const decrypted = CryptoJS.AES.decrypt(
{ ciphertext },
key,
{
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv
}
);
return decrypted.toString(CryptoJS.enc.Utf8);
}
⚠️警告:CryptoJS 的 parse 行为易出错;密钥长度不符会静默失败;不推荐用于新项目。
处理密钥协商与敏感信息防护
前端永远不该硬编码密钥,也不该从不可信来源加载密钥:
- 登录成功后,后端可返回一个临时 AES 密钥(用 RSA 公钥加密传输),前端用私钥(或由服务端托管)解出,再解业务数据
- 更安全的做法是:敏感解密逻辑放在后端,前端只请求“已解密结果”,避免密钥和算法暴露
- 若必须前端解密,请确保密钥通过 HTTPS 安全传输,且不在 DevTools 控制台、日志或 source map 中泄露
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南









