前端加密绕过实战:从识别加密逻辑到接口漏洞测试 📅 发布时间:2026/9/21 2:19:49 👁 浏览次数: 1. 前端加密在拦谁先搞懂漏洞测试为什么会被卡住做渗透测试的朋友一定遇到过这种场景目标系统开了登录接口密码在浏览器开发者工具里看到的是明文但在Burp Suite里面抓到请求包发现password字段全是一长串看不懂的密文。你以为是自己抓包姿势不对改了密文里的一个字符再放行服务器直接给你返回“参数错误”。这时候如果有人告诉你“你得先把payload加密之后再发过去”你可能会更懵这前端加密到底是绕过了还是没绕过先说清楚一个事实前端加密从来不是为了“绝对安全”设计的。它就是一道前置的“门禁”目的是让攻击者不能直接用明文去操作接口。服务器拿到密文以后自己会解密、再校验所以真正的业务逻辑漏洞SQL注入、越权、逻辑绕过等其实还存在于后端只是你只能看到密文没办法直接把注入语句塞进去。换句话讲前端加密拦的不是“漏洞”而是“你直接测试漏洞的这条路”。我见过不少新手在这个阶段选择放弃觉得目标系统“加密做得好、很安全”。但换个角度想如果前端加密真的能挡住漏洞那为什么还能反复爆出验证码绕过、短信轰炸、优惠券薅羊毛这些大新闻因为这些漏洞的攻击面根本不在加密本身而是在加密之后的业务逻辑上。只要你能想办法在正确的位置、以正确的方式把测试数据送到服务器后面的测试内容跟普通Web渗透测试几乎没有区别。所以这篇文章的定位就是把“被前端加密拦住之后怎么办”这件事讲透。我会从识别加密逻辑、修改前端行为、调用加密函数、构造合法密文等方面走一遍完整的测试链路。这套方法适用于登录接口测试、搜索接口注入、越权测试、ID枚举等场景也是我平时做授权测试时反复用到的套路。适合刚接触Web渗透测试、希望从“只会用工具扫描”进阶到“能自己分析接口逻辑”的读者。2. 先看清你面对的是哪种加密一次完整的加密逻辑识别你不能一上来就想着“绕过”那等于闭着眼睛拆炸弹。我建议按下面这个顺序去识别前端加密的类型和位置整个过程十分钟之内就能完成。2.1 常见前端加密算法与特征识别前端加密绝大多数是依赖JavaScript实现的运行在浏览器环境里。常见类型大致可以分为几类哈希类MD5、SHA1、SHA256等。特征是密文固定长度比如MD5是32位十六进制没有密钥理论上不可逆。常用于密码传输前的摘要处理。对称加密AES、DES、3DES。特征是密文长度跟明文长度有关系可能带填充需要一个密钥。常用于整个请求体的加密。非对称加密RSA、ECC。特征是会生成公钥和私钥一对前端用公钥加密后端用私钥解密适用于密钥交换或密码加密。编码类Base64、Hex、URL编码。严格来说不是加密只是编码一眼就能看出来但很多系统会套几层编码来“增加难度”。自定义混淆有些系统会把加密逻辑写在一起甚至用JavaScript混淆工具处理过需要你花更多时间去还原逻辑。怎么快速判断第一步是看密文的格式。在Burp Suite里面抓到包以后先看加密字段的长度和字符集全是0-9a-f且长度是16、32、64优先怀疑MD5或SHA系列结尾带有“”的大概率是Base64密文长度和明文字节数有明显对应关系比如16的倍数可能是AES密文特别长长度在128字节或256字节左右字符集混乱可能是RSA。我之前测过一个后台系统它的登录密码是“小写字母数字”组成的32位字符串一开始我以为是MD5结果去解的时候发现解不出来。后来看了站点的JS发现它先是把明文密码做了MD5接着又把MD5结果跟一个时间戳拼在一起再做了一次MD5。所以经验是只看密文长度可以缩小范围但不能确定算法必须配合JS代码来确认。2.2 用开发者工具定位加密函数打开浏览器开发者工具F12切到Sources源代码面板然后刷新页面看加载了哪些JavaScript文件。不要急着去读所有文件先在全局搜索框里搜几个关键词encrypt加密decrypt解密AES、RSA、DES、MD5setPublicKey、publicKey公钥相关CryptoJS一个非常常见的前端加密库如果你看到引用了CryptoJS这个库那么加密算法基本就是AES、DES、SHA系列这些标准算法如果看到jsencrypt这个库那就是RSA加密。我见过不少系统直接把整个库文件打进来了一眼就能认出来。定位到具体函数之后在Sources面板里给加密函数那行打一个断点。然后回到页面随便输入一个测试账号密码点击登录。当JS执行到加密函数的位置时程序会自动断住。此时你可以在右侧的Scope作用域面板里看到当前变量的值比如明文密码、密钥、加密后的结果等。这样你就能弄清楚整个加密过程明文进去经过哪几步变换最终变成什么密文。这一步做完你对目标加密逻辑的理解应该达到90%以上。剩下10%是某些系统会把密钥动态获取比如从某个接口拉取一个token再当密钥用。这个我们在第4章里专门讲。3. 绕过前端加密的几条路线从改JS到直接调加密函数识别完加密逻辑接下来就是动手阶段。根据测试场景不同绕过方式也不同。我把常见的情况分成五类按优先级排序你在实战中可以先从最容易操作的开始试。3.1 最简单的方式直接修改前端代码有些系统的前端加密就是把登录按钮绑定了一个加密函数你修改页面上的JS代码让它在提交请求前不加密或者在加密后顺手把明文也放进请求里这样Burp里就能看到明文参数。听起来很暴力但确实有效。操作大概是这样在开发者工具的Sources面板里找到加密入口函数右键点击“Overwrite content”或者直接用本地替换Snippets功能改代码。把它加密完的返回值改成明文或者干脆在加密函数下加一行console.log(明文 password)先确认明文在内存里的位置。然后你在控制台手动调用加密函数生成密文把密文拿到Burp里面去替换掉原有密文即可。这里有一个关键点修改前端JS只会影响当前页面的运行服务器完全不知道你改了前端。所以如果你改了页面上的加密逻辑并且页面上其他功能依赖这个加密函数那有可能会引起报错。我建议修改前先保留原JS代码测试完立即恢复。3.2 直接调用加密函数拿到合法密文这是我最推荐的通用方案。既然服务器只认密文那你就在浏览器控制台里主动调用站点本身的加密函数把你想发的payload加密成合法的密文然后把密文放进Burp重新发送。具体来说如果前端用了CryptoJS库控制台执行CryptoJS.AES.encrypt(admin or 11, key).toString()就能生成一个合法的AES密文。如果用了jsencryptvar encryptor new JSEncrypt(); encryptor.setPublicKey(publicKey); var encrypted encryptor.encrypt(admin or 11);关键是函数名和参数顺序。这些信息在你打完断点之后就已经全部暴露了所以识别环节一定不能省。这种做法的优势是你不需要修改页面任何代码服务器收到的密文跟正常用户生成的一模一样校验也能通过。缺点是需要你在控制台做一次“加密测试”然后再把结果复制到Burp里。遇到参数多、字段多的情况效率会有些低所以更推荐配合Burp插件自动化处理。3.3 在Burp Suite里加解密要改包的话这样最省力Burp Suite的“插件机制”提供了BoringsBurp等第三方扩展里面的cyber-chef之类的处理器可以在请求和响应之间自动加解密。不过大多数国产系统加解密逻辑复杂内置处理器不一定匹配。我自己常用的做法是写一个小的Burp扩展插件逻辑不复杂请求发出前用Python或Java调用同样的加密算法处理payload再替换到请求参数里。这个方法的好处是可以在Intruder爆破的时候自动加密每个字典值不用你手动一条条去加密。坏处是对编程能力有一点要求。不过如果你只是做少量测试用Python脚本跑一遍字典生成一份“明文-密文对照表”然后把加密后的列表导入Burp的payload里面也能达到同样效果。提示调用加密函数生成密文的时候注意有些系统会加入时间戳、随机数或者会话绑定。如果密文里包含时间戳你离线生成一大把密文后发现服务器不认很可能就是这个原因。这种情况可以考虑在浏览器里直接用控制台生成或者用脚本模拟一个同样的随机源。3.4 如果密钥是从接口动态获取的怎么处理不少系统为了“安全”不会在前端JS里写死密钥而是登录前先请求一个接口拿一个token、一个时间戳或者一个随机key然后拿这个key作为AES密钥或RSA公钥去加密。遇到这种动态密钥直接离线加密就不太行了因为你每次拿到的key可能都不一样。解决办法是分两步第一步用Burp手工发一次完整的前置接口请求拿到当前这次会话的key第二步在控制台里把key填进加密函数生成密文然后立刻用Burp发送这个密文。由于前端是“拿key → 加密 → 提交”一气呵成的你只要在几步之内完成操作服务器多半不会做额外的时效校验。如果时效校验严格可以尝试修改页面JS把加密后的密文临时存到window全局变量里然后再在控制台手动改值这样能争取一点时间。3.5 绕过之后别忘了核心还是要测后端逻辑前面这些操作本质都是为了把测试数据“翻译”成服务器能识别的格式。等你能正常往服务器发送数据了接下来的测试跟普通接口测试就一样了SQL注入、XSS、越权、ID枚举、水平权限、逻辑绕过该测的都要测。前端加密并不能拦截这些后端漏洞它只能拦住你输入明文。一旦你能生成合法密文漏洞面就全打开了。我遇到过不少系统前端加密做得很认真AESRSA都上了结果登录后的“查看用户详情”接口直接能用另一个用户ID换取他人信息妥妥的水平越权。这说明什么说明那次测试真正的突破口根本不在登录接口而是在业务接口上。你花大力气去搞前端加密不如先把加密这关过了然后把精力集中在后面的业务逻辑测试上。4. 实战记录被AES加密折磨的登录接口我是怎么拿下漏洞点的说了这么多理论来一个完整案例。我在本地搭过Pikachu漏洞测试平台也改过几套自己的靶机环境其中有一台刻意加了一套前端AES加密来模拟真实系统的样子。接下来我按当时的操作顺序把完整过程整理出来。4.1 环境准备与抓包观察目标站点是经典的登录接口。打开浏览器输入账号密码在Burp里打开拦截点击登录。抓到如下请求POST /login HTTP/1.1 Host: 192.168.1.10 Content-Type: application/x-www-form-urlencoded usernameadminpassword7c4c3f0b8c8e1a2b3c4d5e6f7a8b9c0dusername是明文password是一段32位十六进制字符串。从长度和字符集看MD5的可能性最大但我没有急着下结论而是先去看了JS。打开开发者工具Sources面板里发现一个login.js文件内容不长核心逻辑如下function encryptPassword(pwd) { var key CryptoJS.enc.Utf8.parse(1234567890123456); var iv CryptoJS.enc.Utf8.parse(abcdefghijklmnop); var encrypted CryptoJS.AES.encrypt(pwd, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); }原来是AES-CBC加密不是MD5。32位十六进制是因为Base64编码后的密文被转成了十六进制字符串。密钥和偏移量都写在JS里了是硬编码的这给测试省了很多事。4.2 在控制台手动加密payload我直接打开控制台手动执行同样的加密逻辑var key CryptoJS.enc.Utf8.parse(1234567890123456); var iv CryptoJS.enc.Utf8.parse(abcdefghijklmnop); var encrypted CryptoJS.AES.encrypt(admin and 11, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); encrypted.ciphertext.toString();拿到密文之后复制到Burp的password字段发送请求服务器返回了一串正常业务逻辑下的SQL报错。说明我的payload成功进入了后端SQL查询前端加密被完全绕过了。4.3 自动化生成一批payload密文单条手工测试只能验证可行性后面要测SQL注入的深度和注出数据量不可能一条条去控制台加密。我的做法是用Python脚本复现同样的AES加密逻辑批量生成密文。from Crypto.Cipher import AES from Crypto.Util.Padding import pad import base64 key b1234567890123456 iv babcdefghijklmnop def encrypt(payload): cipher AES.new(key, AES.MODE_CBC, iv) padded pad(payload.encode(), AES.block_size) encrypted cipher.encrypt(padded) return encrypted.hex() payloads [ admin or 11, admin -- -, admin union select 1,2,3-- -, admin; waitfor delay 0:0:5-- - ] for p in payloads: print(p, , encrypt(p))这段脚本生成的是十六进制密文跟浏览器控制台生成的格式一致。拿到Burp里放到Intruder的payload列表里直接跑就行。如果目标把密文转成了Base64那就在脚本里输出base64.b64encode(encrypted).decode()按需调整。4.4 遇到动态密钥怎么办继续往前测的时候发现另一个系统的登录接口AES密钥不是写死的而是藏在前置接口返回里GET /api/security-key { key: f8a2c1e3b4d5a6b7c8d9e0f1a2b3c4d5 }前端拿到这个key之后再去加密密码。这种场景下我先把返回的key复制到控制台变量里然后再调用加密函数生成密文。因为key每次可能都不一样所以离线脚本的方法就不太好使了只能借助浏览器控制台手动执行。为了效率我写了一段可以粘贴到控制台的一次性代码把加密逻辑封装成一个函数function enc(pwd) { var key CryptoJS.enc.Utf8.parse(currentKey); var iv CryptoJS.enc.Utf8.parse(abcdefghijklmnop); return CryptoJS.AES.encrypt(pwd, key, {iv: iv, mode: CryptoJS.mode.CBC}).toString(); }然后当前key变了只需要在控制台更新currentKey这个变量再调用enc(admin or 11)就能拿到新密文。整个过程不超过十秒比每秒钟重启一次Burp抓前置接口效率高得多。5. 实战中的那些坑加密字段、编码、会话时效与弱随机数绕过前端加密这件事听起来无非就是“复制加密函数、生成密文、替换发送”但实际操作中会遇到很多细节问题。这部分整理的都是我踩过的坑比其他文章里容易略过的点要实在得多。5.1 注意加密字段的编码问题不少系统的加密结果不是直接用Hex或Base64传输还会再做一层URL编码或者JSON转义。比如Base64编码结果里可能含有、/、这些字符在URL里会被特殊处理。你在Burp里替换密文的时候如果原请求里密文是URL编码后的格式那你替换进去的内容也必须做同样的编码否则服务器解码后拿到的是错误密文。我之前就遇到过这个坑脚本生成的Base64密文里有一个号直接放进请求服务器返回解密失败。排查了一会儿才发现Burp的请求里那个位置被自动做了URL编码变成了%2B。正确做法是发送前先对整个密文做一次URL编码或者在脚本里直接输出URL编码后的结果。5.2 时间戳和随机数的陷阱为了防重放很多系统会在加密内容里塞入时间戳、随机数或者会话ID。你抓到的是一个含有时间戳的密文如果你把密文复制出去隔了三五分钟之后再放回Burp发送服务器校验时间戳已经过期会直接拒绝。遇到这种情况最稳妥的方案是实时生成在浏览器控制台里执行加密函数立即把结果复制到Burp马上发送。如果系统对时间窗口卡得很严比如限定2秒内那就要考虑用Burp插件或者Python脚本在发送前自动调用加密函数生成新密文并把时间戳这部分动态更新进去。5.3 弱随机数和固定IV的判断有些系统的IV是固定的甚至直接硬编码在JS里如上面那个例子。这带来一个典型问题同一个明文在不同时间生成的密文完全一样。此时你可以用已知明密文对去推测密钥或者在爆破的时候直接爆破明文密文不用变因为密钥和IV固定了穷举效率会高很多。反过来如果系统使用了随机IV那么同一个明文每次加密后密文都不一样这时候你在爆破的时候就要给每个payload单独生成新IV和新密文否则服务器会因为IV不符而拒绝。识别方法很简单连续提交两次相同密码观察密文是否相同。相同说明IV固定或使用ECB模式不同则说明大概率是CBC模式加随机IV。5.4 JS压缩与混淆代码的处理真实系统里的前端JS往往经过压缩所有变量名都变成了a、b、c这样的短名字函数名也可能被改掉。遇到混淆得比较厉害的JS直接在Sources面板里读代码会很痛苦。我建议先去找这个站点是不是用了webpack或类似的打包工具如果是很多模块会被合并成一个大的bundle文件里面有大量代码。这时候优先利用控制台而不是去阅读源码。你可以在控制台里执行CryptoJS相关对象的方法如果库还在全局范围内直接调用就行。如果库被包在某个模块里没有暴露到全局那就需要去页面源码里搜索关键词比如“encrypt”定位到具体位置在那个函数上打断点通过运行时的调用关系去获取密钥或明文。我自己的习惯是先打断点再看调用栈最后才去读源码。断点能直接告诉你这个函数被谁调用、传入什么参数、内部变量是什么值。这比站在源码外面猜要快得多。5.5 别忘了会话绑定问题有些系统的加密密钥虽然在前端JS里写死了但服务器端在实际解密之后还会校验密钥是否属于当前会话。比如登录接口的加密密钥可能是“临时token固定密钥”拼接出来的token由另一个接口下发给当前浏览器。如果你把密文从Burp里复制走换一个环境发送token可能对不上服务器就会返回校验失败。这种场景下你要做的不是在Burp里改密文而是把目标站点页面上JS里的token取出来跟后续业务接口的token对比看看它们是否是同一个值。如果是同一个那加密逻辑和会话逻辑就绑定在一起了测试的时候需要保证整个流程都发生在同一个会话内。我的做法是全程通过浏览器操作交互Burp只做流量观察只有确认具体要测某个接口时才在Burp里单独构造请求并同时从页面里抓取当前token补进去。6. 前端加密封不住的是业务逻辑为什么还是要把重心放在接口层前端加密这道关卡说到底只是增加了测试的前期成本。真正决定系统安不安全的仍然是后端接口的逻辑是否严密。我做了这么多年授权测试见过太多“加密做得很花哨、业务逻辑烂成一团”的系统。前端加密能拦住脚本小子但拦不住真正愿意去分析交互逻辑的人。举几个实际见过的例子某系统登录接口做了AES加密但注册接口完全没加密而且注册接口存在用户枚举漏洞通过返回信息能判断某个手机号是否已注册。某系统所有前端参数都加密但有一个导出功能导出请求里的参数是明文而且没有做权限校验普通用户可以导出管理员数据。某系统密码加密很扎实但密码找回接口只校验“用户名密保问题答案”而且密保问题答案可以直接通过另一个未加密接口获取。这些漏洞都是在前端加密之外暴露出来的。所以我的观点是遇到前端加密不要一头扎进去研究怎么破解它而是先把它当作一个“提示”——提示你重点测哪些接口有保护哪些接口可能没有保护。测试顺序上优先测那些没有加密的接口、暴露参数更多的接口、涉及业务操作的接口。前端加密的接口集中在登录、支付、个人信息等核心位置对应的后端逻辑往往相对完善反而是那些“看起来不重要的”业务接口更容易出现越权、枚举、逻辑绕过这类问题。在实际授权测试里我花在前端加密上的时间通常不会超过整个测试周期的20%剩余时间都用在业务功能测试、权限绕过和漏洞利用上。前端加密只是第一道门门开了之后里面的世界才刚展开。提示本文所有方法仅用于授权测试、漏洞挖掘学习、安全加固自查等合法场景。未经授权对他人系统进行测试属于违法行为。建议想练手的朋友优先使用Pikachu、DVWA等本地漏洞靶场或在有书面授权的环境中操作。安全测试的第一原则是合法合规。