web安全代码基础-JavaScript(JS-数据加密安全)
目录
CryptoJS(MD5/AES/DES/HMAC)前端加密安全漏洞
漏洞 1:对称加密(AES/DES)密钥硬编码在 JS,攻击者直接提取密钥解密 / 伪造密文
漏洞 2:MD5/SHA1 仅做加密,无随机盐、无请求签名,可碰撞 / 批量伪造
漏洞 3:HMAC 使用固定密钥,前端泄露密钥后可伪造任意签名
漏洞 4:前端加密仅防窃听,后端缺失二次业务校验(最普遍高危漏洞)
漏洞 2:RSA 单次加密长度有限,分段加密易被篡改、拆分绕过
漏洞 3:依赖前端生成随机向量 / 随机数,随机因子可控可预测
1. 前端对称加密(CryptoJS AES/DES/MD5/HMAC)致命短板
前端JS数据加密核心疑问操作
安全测试修改数据包发生在哪一步?
非加密流程修改位置
流程:客户端明文 → 网络传输明文 → 服务端接收
修改点:网络传输阶段(抓包工具 Burp/Charles/Fiddler 拦截请求)
- JS 只是把明文直接放进请求体 / 参数发送;
- 中间人拦截 HTTP 请求,直接篡改明文参数再转发给后端。
示例:前端直接提交金额money=100,抓包改成money=0.01提交,后端无校验直接生效。
前端加密流程修改位置(关键)
流程:明文前端 JS 加密 → 传输密文 → 后端解密处理
两种修改场景:
场景 1:篡改密文(无签名校验,后端仅解密不校验原始数据合法性)
修改阶段:网络传输阶段拦截,直接替换密文字符串发包。 后端解密后拿到篡改数据,业务沦陷。
场景 2:逆向前端加密逻辑,构造合法密文(最常用渗透手段)
修改阶段:客户端 JS 加密之前
- 安全测试人员 F12 拿到 CryptoJS/jsencrypt 加密源码、密钥、盐值;
- 本地逆向复现加密算法,手动构造恶意明文 → 加密生成合法密文,再发包; 后端无法区分是正常页面加密还是黑客手动构造的密文。
核心结论
前端加密不能防止抓包篡改,只能防止传输明文窃听,无法抵御中间人篡改攻击。
CryptoJS(MD5/AES/DES/HMAC)前端加密安全漏洞
漏洞 1:对称加密(AES/DES)密钥硬编码在 JS,攻击者直接提取密钥解密 / 伪造密文
// 前端危险代码(AES 加密,密钥写死在前端)
<script src="crypto-js.min.js"></script>
<script>
// 密钥明文硬编码在JS,任何人F12可见
const KEY = CryptoJS.enc.Utf8.parse("1234567890123456");
const IV = CryptoJS.enc.Utf8.parse("1234567890123456");
function encrypt(text){
return CryptoJS.AES.encrypt(text, KEY, {iv:IV}).toString();
}
function decrypt(cipher){
return CryptoJS.AES.decrypt(cipher, KEY, {iv:IV}).toString(CryptoJS.enc.Utf8);
}
// 提交订单金额加密
let money = document.getElementById("money").value;
let cipherText = encrypt(money);
// AJAX发送密文给后端
$.post("/pay", {data:cipherText})
</script>
攻击流程
1、F12 查看源码拿到KEY=1234567890123456;
2、本地调用同一套加密函数,构造恶意金额money=0.01;
3、生成合法密文,Burp 拦截替换请求里的data参数提交;
4、后端用相同密钥解密,收到篡改金额,直接扣款。
漏洞 2:MD5/SHA1 仅做加密,无随机盐、无请求签名,可碰撞 / 批量伪造
// 错误用法:仅对参数 MD5 加密,后端只解密不校验完整性
// 前端对订单ID简单MD5
function getMd5(id){
return CryptoJS.MD5(id).toString();
}
let orderId = 10001;
let sign = getMd5(orderId);
$.post("/api/order", {orderSign:sign})
风险
MD5 不可逆但可枚举彩虹表,攻击者遍历订单 ID 批量生成签名,遍历查询所有用户订单; 若后端仅校验 “字符串是合法 MD5”,不绑定会话 / 随机盐,完全失去防护意义。
漏洞 3:HMAC 使用固定密钥,前端泄露密钥后可伪造任意签名
// HMAC 设计本意是做数据完整性校验,但密钥放前端直接失效:
const hmacKey = "mysecret123";
function getHmac(data){
return CryptoJS.HmacSHA256(data, hmacKey).toString();
}
// 请求参数 + hmac签名一起发送
let data = "money=100";
let sign = getHmac(data);
$.post("/pay", {data, sign})
风险
攻击者提取hmacKey,自行构造data="money=0.01"并生成合法 sign,后端无法分辨数据被篡改。
漏洞 4:前端加密仅防窃听,后端缺失二次业务校验(最普遍高危漏洞)
哪怕加密算法无漏洞,只要后端不校验业务逻辑,篡改密文后依然能越权:
前端加密用户 ID:userId=1001加密传输;
攻击者逆向加密逻辑生成userId=1002密文发包;
后端解密拿到 1002,直接返回他人订单数据 → 水平越权。
漏洞 5:DES 弱加密算法安全性极低
DES 密钥短(56 位),可暴力破解,前端使用 DES 极易被快速破解密文。
jsencrypt RSA 非对称前端加密安全漏洞
RSA 逻辑:公钥放前端加密,私钥保存在后端解密。
漏洞 1:仅加密业务参数,未做请求签名,依然可篡改参数逻辑
// 错误示例:只加密金额,请求其他参数明文传输
<script src="jsencrypt.js"></script>
<script>
// 公钥公开写在前端
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
6rPJj+CvfSC8+2qYuJH+j7khFcnX5QA+N4hK03sIfxBVDvQZvODA/vwf44r1BHfr
MzdrO7blaKEAAQekKsYzkElRWwH0vsyjEZqy9WRU+vVrZ5kSTnHx+Hvz3o/WGObAEV
5rypMxb9q4vM14qFevzhtXeoQIDAQAB
-----END PUBLIC KEY-----`;
let encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
let money = $("#money").val();
let cipherMoney = encrypt.encrypt(money);
// userId明文传输,仅money加密
$.post("/pay", {userId:1001, money:cipherMoney})
</script>
攻击方式
Burp 抓包修改明文userId:1002,加密金额不变;后端解密金额正常,同时读取篡改后的用户 ID,操作他人账户。
漏洞 2:RSA 单次加密长度有限,分段加密易被篡改、拆分绕过
jsencrypt RSA 加密有明文长度上限,开发会拆分长文本分段加密,攻击者可修改其中一段数据,后端拼接后逻辑错乱。
漏洞 3:依赖前端生成随机向量 / 随机数,随机因子可控可预测
若前端自行生成加密随机因子用于签名,攻击者复现随机规则,批量伪造合法请求。
漏洞 4:后端无会话绑定校验,加密数据可复用(重放攻击)
攻击者抓一次合法加密请求,反复重复发包(重复扣款、重复提交表单);
仅靠 RSA 加密无法防御重放,必须增加时间戳、一次性 nonce 随机数做签名校验。
漏洞 5:公钥可替换中间人攻击(无证书校验)
如果网站没有 HTTPS,中间人劫持页面替换前端公钥为黑客私钥对应的公钥;
前端加密的数据黑客可解密窃取,再用真实公钥加密转发给服务器,全程窃听篡改。
JS 代码混淆的安全局限性与安全问题
JS代码混淆为保护前端JS代码不被轻易逆向,但是也会产生安全问题
1. 混淆只能提升逆向成本,无法防止逆向解密加密逻辑
混淆本质只是修改变量名、压缩代码、增加无效僵尸代码,算法逻辑完全保留。
原始清晰代码:
function getAesCipher(text){
let key = "admin123456";
return CryptoJS.AES.encrypt(text, key).toString();
}
混淆后代码示例:
var _0x123a=["admin123456","encrypt","toString"];function _0x45b(_0xc1){let _0x22=_0x123a[0];return CryptoJS.AES[_0x123a[1]](_0xc1,_0x22)[_0x123a[2]]()}
漏洞
1、使用反混淆工具(js-beautify、在线解混淆网站)一键格式化还原代码;
2、正则匹配CryptoJS.AES.encrypt、JSEncrypt关键字,快速定位加密密钥与算法;
3、密钥、加密逻辑依然完整暴露,混淆不能保护前端密钥。
2. 混淆无法拦截抓包篡改请求
混淆只是修改 JS 代码可读性,网络传输的密文 / 请求参数完全不受影响;
Burp 依然可以拦截、替换请求数据,混淆对中间人攻击完全无效。
3. 混淆存在调试防护绕过
市面上混淆工具常用 debugger 无限循环阻止开发者调试控制台:
setInterval(function(){debugger;},100);
绕过手段
浏览器控制台勾选「禁用调试器」,直接跳过防护,正常断点分析加密逻辑。
4. 压缩混淆会掩盖恶意后门 / 隐藏漏洞
业务 JS 混淆后,隐藏高危逻辑(硬编码密钥、后门接口)难以快速审计;
恶意攻击者可植入僵尸函数、隐藏窃取 Cookie 代码,审计人员难以快速识别风险。
5. 混淆不改变前端不可信核心问题
攻击手段
无论混淆多复杂,JS 运行在用户浏览器,攻击者拥有完整控制权:
1、控制台覆盖加密函数,直接输出明文;
// 控制台执行覆盖原有加密函数,直接拿到原始明文
function _0x45b(text){
console.log("原始明文:",text); // 打印要加密的原始数据
return 原来的加密结果;
}
2、删除、重写加密逻辑,自定义恶意密文提交。
统一总结三大类技术核心安全缺陷
1. 前端对称加密(CryptoJS AES/DES/MD5/HMAC)致命短板
1、密钥必须存放前端,攻击者 100% 可提取;
2、仅加密传输内容,无数据完整性校验,中间人可篡改;
3、无法防御重放、越权、业务逻辑绕过;
4、仅能解决 HTTP 明文窃听,不能做权限 / 数据防篡改防护。
2. 前端 RSA 非对称加密(jsencrypt)短板
1、仅加密参数无法保护整个请求,明文参数易被篡改;
2、无时间戳 / 随机数防护,存在重放攻击;
3、HTTP 环境下存在公钥劫持中间人风险;
4、长文本分段加密存在篡改漏洞。
3. JS 代码混淆的本质局限
1、仅增加逆向时间成本,不能阻止逆向;
2、无法保护密钥、加密算法;
3、无法防御抓包篡改请求;
4、调试防护可一键绕过。
修复方案
1、区分加密作用:前端加密仅用于防止传输窃听,防篡改、权限校验必须放在后端;
2、数据完整性防护:后端使用后端私钥生成全局签名(包含全部参数 + 时间戳 + 会话 ID + 随机 nonce),前端仅传参,签名由后端计算校验;
3、密钥管理:对称密钥、RSA 私钥绝不前端存放;敏感参数加密、签名计算全部后端完成;
4、业务双重校验:解密后后端二次校验用户身份、金额、权限,不能只依赖前端传入数据;
5、防重放:请求携带时间戳 + 一次性随机数,后端校验有效期,拒绝重复请求;
6、HTTPS 强制部署,杜绝中间人劫持替换公钥;
7、混淆仅作辅助,不能作为安全防护手段,核心加密逻辑移至后端接口处理。
更多推荐
所有评论(0)