ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

前端加密并非安全边界:渗透测试中的绕过思路与实战技巧

前端加密并非安全边界:渗透测试中的绕过思路与实战技巧 这标题确实是个“民工级”痛点。我见过不少人拿到一个目标站点看到登录请求加密、参数全是密文直接就懵了觉得“这玩意没法测了”。其实前端加密这层窗户纸捅破之后你会发现后面的逻辑漏洞比想象中多得多。先说清楚一个核心事实前端加密不是安全边界。它本质上是“防君子不防小人”的锁用来挡挡闲逛的脚本、防止密码明文落进日志、降低撞库扫号的效率。但真正决定系统安全的永远是后端对数据的信任程度和处理逻辑。这篇文章我就从测试者的实际操作出发聊聊遇到前端加密时怎么一步步把漏洞测试做下去顺便把每个环节的原理和坑都讲透。1. 前端加密不是安全边界先搞清楚它到底挡了什么很多入门者会对“加密”两个字产生敬畏觉得加密就等于安全。这个认知必须纠正过来。前端加密的核心只是“在浏览器端把数据变成密文再把密文传给服务器”它能影响的是传输过程中的可读性但它改变不了下面几个残酷的事实算法和密钥必然暴露在浏览器里。你用JavaScript写的加密逻辑用户按一下F12就能看到源码。不管是RSA的公钥还是AES的密钥和IV都躺在Script文件里等着被翻。服务器必须能解密。既然后端能还原数据就说明加密是双向可逆或存在对应私钥的绕过思路就有了落点。加密只覆盖了请求体。URL路径、Cookie、Referer、Header大部分时候还是明文或可修改的照样能测。我习惯把前端加密比作“把信塞进保险箱再递给邮递员”。听起来很安全对吧但问题是这个保险箱的钥匙就挂在箱子外面而且收件人必须能打开它。邮递员中途能不能打开只要能拿到挂在箱外的钥匙他就能看信、改信、再原样锁回去。1.1 前端加密的实际作用其实很有限搞清楚这层逻辑之后前端加密的真实作用其实只剩下这几个降低数据被中间人直接窃取的可读性。注意是“降低”因为HTTPS本身已经解决了传输加密问题前端再套一层防的主要是那些不装证书、直接抓明文HTTP流量的初级攻击者。防拖库撞库。密码在被传出去之前就变成了密文攻击者即使截获了请求也没法直接拿这个密文去别的平台撞用户名密码。但这只是临时挡箭牌因为后端数据库里存的如果是同样的可逆密文或者干脆不校验密文格式照样撞。防自动化脚本。默认的爬虫和扫描器发送的是明文请求遇到加密接口会直接失效。这客观上劝退了一批低水平扫描器但拦不住手工测试和一键绕过的脚本。1.2 对测试者的启示先侦察别急着破解正确的前端加密测试流程不是坐下来硬破解密文而是先回答四个问题哪些参数加密了是全部请求体加密还是只有密码字段加密加密是在哪个环节发生的表单提交前?Ajax发送前后端是否真的校验了密文有时候你直接发明文后端也照常响应说明加密纯属摆设。密文里有没有服务端可控的部分比如时间戳、随机数、用户ID、订单号这些才是绕过加密的重点。把这四个问题摸透了直接决定了你后续要用哪种绕过方案。我很明确地说我遇到的前端加密系统里至少有三分之一的案例加密形同虚设——后端根本没做任何完整性校验直接把收到的明文当业务数据用。2. 动手之前先把测试边界划清楚靶场与授权在往下聊绕过技巧之前我得先敲一下黑板。渗透测试是合规职业行为不是随便找个网站练手的行为。没有目标方的书面授权就去做测试哪怕动机再纯也属于越界。这不是套话是这条路上真正会让人栽跟头的地方。我自己的习惯是所有前端加密的绕过练习一律在本地靶场环境里进行。想验证技术、练手、跟同行交流用下面几个靶场足够了Pikachu靶场有个专门的“不安全加密”模块能练Base64、对称加密等场景适合入门。DVWA老牌靶场改低安全级别之后可以模拟从明文到弱加密的转换方便对照测试。WebGoatOWASP官方出的靶场里面有专门的加密绕过和JWT伪造课程逻辑链很完整。本地自建Demo如果上面的靶场不够贴近真实系统我建议自己起一个Node或Python后端写一个前后端分离的登录页用CryptoJS在前端做AES加密、后端解密。只要半小时就能搭好之后所有技巧都能在这个自建环境里反复练。工具准备方面装一套基础链就行Burp Suite Community/Pro代理拦截和改包的主力工具必装。Chrome DevTools下断点、改JS、看调用栈、执行Hook代码全要靠它。Fiddler / mitmproxyFiddler处理Windows上的HTTPS解密更顺手mitmproxy适合脚本化操作。Node.js环境验证密钥、写解密脚本、跑算法还原时离不开它。Frida可选如果目标环境是App或嵌套了原生加密逻辑Frida做运行时Hook的效果很好纯Web场景可以先不碰。把靶场搭起来工具装好再往下走。后面的所有操作示例都默认你已经在本地靶场或已获授权的测试环境里了。3. 绕过的第一步不是解密是把浏览器变成解密机遇到前端加密时我第一件事就是掏出Chrome DevTools直接在浏览器里把加密前的明文“钓”出来。这个思路的核心是既然加密逻辑在浏览器里跑那我就在浏览器里把过程完完整整地看一遍甚至篡改一遍。根本不需要一开始就对着密文头大。3.1 三步定位加密函数怎么找到加密函数方法很暴力也很有效。第一步看网络请求找加密的入口和出口。打开DevTools的Network面板勾选Preserve log然后正常登录一次。点开登录请求的Payload看加密的是整个请求体还是单独的字段。同时记下发起请求的JS文件名。第二步在Sources面板里全局搜索加密特征关键词。常用关键词包括encrypt、decrypt、AES、RSA、CryptoJS、setPublicKey、Base64、btoa、ajax提交函数等。搜索不到就搜password、sign、signature这类业务字段名多半能找到赋值和加密的位置。第三步给加密函数下断点。在Sources面板里定位到函数位置点击行号设置断点回到页面重新提交一次表单。请求会被浏览器拦停停在调用加密函数的前一刻。这时候鼠标悬停到变量上明文内容直接就在眼前。3.2 用Hook把加密函数“摊开”给你看断点看一次是可以的但如果每次请求都要手动停一次效率就太低了。更好用的方式是Hook加密函数把明文和密文一起打印到控制台。原理非常简单在加密函数调用之前先用一段脚本把它包一层。以常见的CryptoJS AES加密为例假设原代码是这样function encryptData(plainText) { var key CryptoJS.enc.Utf8.parse(0123456789abcdef); var iv CryptoJS.enc.Utf8.parse(abcdef9876543210); return CryptoJS.AES.encrypt(plainText, key, { iv: iv }).toString(); }我在控制台里这样Hookvar originalEncryptData encryptData; encryptData function(plainText) { console.log([HOOK] 加密前明文:, plainText); var cipherText originalEncryptData(plainText); console.log([HOOK] 加密后密文:, cipherText); return cipherText; };页面再发请求时控制台就会自动打出一对明密文一次都不用断点了。提示如果encryptData是挂在某个对象下的方法比如App.Crypto.encryptData就改成App.Crypto.encryptData function(...) {...}的形式去替换。3.3 更进一步的思路直接篡改加密函数的返回值看明文只是第一步。有时候我们想测的漏洞是“这个后端到底校不校验签名”那就可以直接改Hook函数的返回值比如固定返回一个攻击者可控的密文或者干脆用别人会话里的合法密文替换掉当前请求中的所有密文。var originalEncryptData encryptData; encryptData function(plainText) { var cipherText originalEncryptData(admin:1:20240101); console.log([HOOK] 固定替换密文:, cipherText); return cipherText; };如果你发现替换成伪造密钥加密后的密文后端还能正常返回数据那说明后端压根没做密钥管理或完整性校验这本身就是个高危问题。4. 代理工具链的改造思路让你发的请求真正可控DevTools解决的是“看”的问题但真正要实打实地改参数、改密文、发重放还是得靠代理工具把请求流程管起来。这里有两个截然不同的层次普通的抓包改包和更暴力一点的JS替换。4.1 先把HTTPS流量解密成明文不管用Burp还是Fiddler第一步永远是配置证书让工具能解密HTTPS。这一步经常有人卡住我简单说下要点用Burp Suite启动代理后访问http://burp下载CA证书安装到系统受信任的根证书颁发机构。手机测试的话要同时把CA证书装进设备并确保App/浏览器信任用户证书。装完证书后浏览器访问任意HTTPS站点不再报证书错误就说明解密生效了。这一步做完Burp的HTTP History里就能看到完整的请求、响应体。如果请求体是密文没关系我们下一步处理。4.2 抓包改包的判断逻辑密文里藏着哪些可改参数拿到密文请求后先别急着改。我通常会先发送几次不同操作对比密文之间的差异。举个例子同一接口用户名从admin换成test密文长度和前缀如果发生变化说明密文里包含了用户名且大概率是可逆的如果两次密文完全一样说明加密函数可能没用到随机IV重放攻击会特别好打。改包的核心操作就是在Burp的Repeater里把密文替换成别的内容然后观察响应差异。分发几种典型结果操作响应表现结论完全复制上一轮密文重放返回成功存在重放风险后端无时效校验对密文做任意字节修改报解密失败/500后端会解密说明密文参与业务计算把密文改成明文直接提交正常返回后端压根没解密校验加密是摆设改了密文特定位置后解密成功但数据变化密文中的业务数据可篡改存在越权可能4.3 替换JavaScript文件直接让前端发送明文有些场景下发密文的加密后端校验得非常严手动改包很费劲。这时候就该上“前端改造”路子把测试流量中的JS文件替换成自己的版本让浏览器发明文。Burp Suite里有一个非常实用的模块叫Match and Replace配合Proxy Options里的Content-Type过滤可以做到对特定响应内容做实时替换。具体做法是在Burp的Proxy Options里打开Match and Replace规则。新增一条规则匹配URL中包含crypto.js或encrypt.js的响应。Replace动作设成加载本地文件内容是你已经改好的、去掉了加密逻辑的JS。我把这种做法叫作“前端降级”。这种操作不是为了让浏览器失败而是为了直观地检验一个核心问题当系统不存在前端加密时后端的行为是否跟有加密时一致这个问题的答案直接决定了加密到底是增厚了安全层还是纯属装饰。注意替换JS文件只在你自己的浏览器/测试机里生效不会影响其他用户也不会对目标系统的真实环境造成任何污染。这也是为什么它特别适合测试阶段的原因。4.4 脚本化的重放与爆破思路对于确认存在重放风险的接口下一步就可以用Burp Intruder或者mitmproxy脚本做批量测试。很多前端加密系统的“签名”字段只是个时间戳加固定盐对时效性完全没做校验。你完全可以用同一个合法密文循环重放测登录接口是否存在账户密码爆破风险、测订单接口是否存在重复提交问题。mitmproxy的Python脚本写法很简单def request(flow): if login in flow.request.url: flow.request.text flow.request.text.replace(passwordencrypted_value, passwordadmin)把这段代码存成modify_login.py启动时用mitmproxy -s modify_login.py所有命中规则的请求都会被自动改写。这种手段用来验证后端是否对加密字段有二次校验效率非常高。5. 分算法拆解不同加密方式有不同的破解思路到这一步讲的是通用的绕过框架但真实项目里加密方式多种多样每种的具体拆解思路也不一样。我按常见程度排个序逐个过一遍。5.1 Base64和自研“伪加密”一眼识破Base64不是加密它只是编码。看到请求体里的字符串以结尾、只包含A-Z、a-z、0-9、、/这些字符时先丢到解码器里看一眼echo dXNlcj1hZG1pbg | base64 -d # 输出: useradmin自研“伪加密”就更常见了很多程序员自己写的“加密”其实就是字符串翻转、按位异或、字符ASCII码加固定偏移这类简单变换。识别方法很简单把同样的明文和密文多抓几组找规律。比如明文admin密文fglqk每个字符偏移量都是5这就是经典的凯撒位移。这类“加密”对测试没有任何难度只要在本地写个还原脚本就行。5.2 AES等对称加密密钥就藏在JS里AES是前端加密里最常见的正主。它是对称加密加解密用同一个密钥而密钥在前端代码里这意味着一定能找到。典型场景是CryptoJS的AES加密密钥和IV都是硬编码在JS里的。找到之后用Node.js的crypto模块就能实现本地解密const crypto require(crypto); const decipher crypto.createDecipheriv(aes-128-cbc, Buffer.from(0123456789abcdef), Buffer.from(abcdef9876543210)); let decrypted decipher.update(cipherText, base64, utf8); decrypted decipher.final(utf8); console.log(decrypted);调试的时候我一般会写一个Node脚本把Burp里抓到的密文批量解密成明文看清请求体的完整结构再决定要改哪个字段。这个工作叫“逆向请求体格式”是后续漏洞挖掘的地基。5.3 RSA非对称加密私钥拿不到就绕道RSA的公钥在前端、私钥在后端你无法直接解密抓到的密文。但这不代表无计可施。常用的思路有两个Hook浏览器的加密过程既然浏览器能加密就让浏览器帮我们干解密的事——不对浏览器也没有私钥。正确说法是让浏览器帮我们干“重新加密”的事我们把明文改成自己想要的值调用页面里的加密函数生成新密文再手动提交。利用反向代理或浏览器插件写一个小插件在表单提交前篡改明文再交给原加密函数处理。这样全程无感后端只会看到一串完全正常的合法密文。这就是为什么我在第3节强调要掌握Hook——遇到RSA时Hook不是可选而是必选。因为你不去调页面里的加密函数就没办法用合法的公钥加密出有效的密文。5.4 反混淆当JS代码被压缩成天书时真实系统里代码往往是混淆过的加密函数不是叫encryptData而是叫_0x3f2a变量全是十六进制名。这时直接搜关键词会搜不到但不必慌有几个常用手段格式化在Sources面板里点左下角的“Pretty print”按钮压缩代码会自动格式化换行。搜索密文特征不搜变量名改搜fromCharCode、charCodeAt、toString(16)这类编码/解码常用的底层方法。加密逻辑哪怕混淆得再厉害底层也不可避免要用到这些API。动态Hook混淆代码没法直接改源码但可以用代理或条件断点拦截任何对CryptoJS或window.btoa的调用从运行时反推逻辑。5.5 解密之后的下一步别停留在“解密成功”把密文还原成明文不是终点。真正有价值的是解密后拿到的那份“结构化的业务数据”。我拿一个实际场景举例某系统的下单接口密文解密后是{userId:1001,productId:2002,price:9.9,timestamp:1699999999}。这时候绕过的目标就很清晰了把price改成0.01再用页面加密函数生成合法密文提交看后端反应。这种案例在授权测试中出现的频率远比大多数人想象的高。6. 密文解不开也没关系重放、篡改与逻辑测试并不是所有前端加密都能被顺利还原。遇到高强度自定义加密或者后端私钥管理得很好时我们还有一套“不解密也能测”的方案。6.1 重放攻击测试只看后端重不重视密文时效前端加密最常被忽视的问题就是重放。很多系统虽然做了加密但密文里根本没有时间戳后端也不校验请求的先后顺序和有效期。测试方法就是最简单的一条把抓到的整个请求保存下来隔几分钟、隔几个小时原样重放如果后端照常处理这个系统就存在重放风险。如果是涉及支付、订单、登录Token的接口重放测试必须作为必测项。我见过真实案例里订单支付接口重放几次业务后端就会多生产几笔订单这种漏洞的定级不会低。6.2 密文篡改和边界测试用黑盒语义探测系统底线如果不知道密钥但你手上有合法的密文样本可以做几类黑盒测试翻转密文的某一位观察响应是“解密失败”还是“正常解密但数据异常”。如果是后者说明密文缺少完整性校验大概率存在数据篡改面。替换关联字段比如A接口的密文段是用户信息B接口的密文段也是同类尝试跨接口重放密文看后端是否做了绑定关系校验。长度测试给密文末尾追加填充字节观察是否会触发后端解密器的报错捕获报错页面里的堆栈或环境信息。这些测试没有一个依赖密钥纯粹通过探测后端的“反应”来判断加密的真实强度实践中非常有效。6.3 绕过加密直接打业务逻辑有时候最蠢的方法反而最有效。我建议你在做任何深度的解密分析之前先花十分钟测试下面的逻辑改方法把POST换成GET、PUT、DELETE后端可能对非预期方法不做参数校验。改Content-Type把application/json改成application/x-www-form-urlencoded有些后端框架对格式解析的宽容度不同可能直接绕过前端校验。删字段把密文中“签名”“验签”这类字段整体删除看后端是否会报错并默认放行。提交空值把密文替换成空字符串、null、0这类边界值看后端解密逻辑是否会因为意外输入而跳过校验。这一套“乱拳”下来经常能打出暴击。原因在于很多后端的加解密代码只覆盖了正常流程没有处理异常输入异常输入会走另一条逻辑分支那条分支往往是没有安全校验的。7. 前端加密过度使用的隐患加密越重逻辑越容易漏最后想聊一个很多人没意识到的点。前端加密应用得越深反而越容易引入额外的高危问题。这个反直觉的结论在授权测试项目里验证了很多次。第一类隐患是前端加密导致后端形成“加密依赖症”。研发可能觉得“前端加密防住了恶意参数”于是后端把所有参数都当成可信数据不做二次校验。这在越权、订单篡改、优惠券套利等漏洞上表现为直接以解密后的明文作为业务判断依据安全校验形同虚设。第二类隐患是密钥硬编码和密钥泄露。如果后端私钥被错误地集成在前端代码里或者前后端共用一套对称密钥这相当于把整座大门的备用钥匙挂在了门口。做前端加密项目时我都会额外检查一遍JS里有没有夹杂后端私钥、API密钥、内部域名等敏感信息。第三类隐患是加密带来隐蔽性让安全监听失效。前端加密后的请求体在网关、WAF、审计日志里全是密文安全设备没法做威胁检测。这种情况下攻击者反而可以利用加密信道做恶意活动而不被发现。对测试者来说一旦发现前端加密也要额外关注后端是否具备解密审计的能力。处理前端加密问题时我的经验是“先降维、再摸底、后打击”。降维是指把浏览器和代理工具的价值用足把明文捞出来摸底是搞清楚后端的信任边界第四条里提到的响应观察法就是典型打击是找到那个“加密之外没设防”的业务逻辑漏洞。不要一上来就对着密文死磕解密算法那是把力气用错了地方。准备一个建好的本地靶场环境用文中的框架练两三轮再遇到前端加密的测试目标你大概率就不会心慌了。这层纸捅破之后后面就是拼耐心和细心的常规活了。
返回列表