news 2026/9/19 12:43:15

JS逆向实战:前端参数加密与算法还原全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JS逆向实战:前端参数加密与算法还原全攻略

做前端数据采集和技术研究的朋友,对JS逆向这个词肯定不陌生。尤其是这两年,你会发现越来越多的网站把核心参数做了加密处理,登录态、搜索参数、翻页参数,几乎每一个关键请求都带着一串看不透的密文。我最初接触JS逆向的时候,就是被这种参数加解密逼出来的——明明浏览器里清清楚楚的数据,换到脚本里请求就直接失败,返回一句“参数错误”或者“签名无效”,那种憋屈感相信很多人都有过。

这篇内容不是教科书式的理论讲解,而是我这些年在实际项目中反复踩坑、反复验证后整理的一整套JS逆向参数加解密处理方法。我尽量用大家都能听懂的大白话,把参数加密的常见形态、定位加密入口的方法、算法识别与还原的思路、以及最终把逆向结果落地成可用工具的全过程讲透。无论你是刚入门的爬虫学习者,还是已经在做接口分析的技术人员,这篇文章都能给你一套可以直接上手的参考方案。特别是那些遇到“搜不到加密函数”“还原算法后签名不对”“代码被混淆到怀疑人生”的朋友,我会把这些问题逐一拆开讲明白。

1. 先搞清楚:你到底在逆向什么

很多新手拿到一个加密参数就开始埋头翻代码,翻了两小时什么也没找到,其实是对目标缺乏最基本的判断。JS逆向参数加解密,本质上做的事情是:一个网页在浏览器里发请求时,JS代码在发送前对某些字段做了一次变换,服务端收到后再做对应的逆变换来校验身份或者保证数据完整性。

1.1 前端参数加密的常见形态

我先列一个清单,这是我在实际项目中遇到的最常见的几种加密形态,后面的所有分析和还原思路都是围绕这些基础形态展开的:

类型代表算法/方式特点可逆性
编码Base64、URL编码字符集固定(A-Za-z0-9+/=),肉眼可见特征直接可解码
哈希摘要MD5、SHA1、SHA256定长输出(32/40/64位十六进制),不可逆不可逆,只能碰撞或查库
对称加密AES、DES、3DES有密钥,密文长度与明文成正比,通常有填充有密钥即可还原
非对称加密RSA有公钥和私钥,密文长度固定(如128字节)有私钥才可还原
国密算法SM2、SM3、SM4国内金融、政企系统高频出现,特征类似RSA/AESSM3不可逆,SM2/SM4可逆
自定义魔改混合编码、自研算法无固定特征,需要在JS里跟读逻辑看具体实现

如何快速判断类型:最简单的方法是看密文本身。Base64编码通常以“=”结尾,哈希值一般就是32位或64位的十六进制字符(0-9和a-f),AES密文是一串不可读的二进制转字符串,RSA密文则明显更长更规整。这种“先看症状再开药”的思路,能帮你节省大量时间。

1.2 为什么会有参数加密,业务和非业务的原因

从业务的视角看,前端参数加密绝对不是无缘无故的设计。理解背后的原因,对你推断加密算法的实现方式非常有帮助。

最常见的目的是防篡改与防重放。比如一个下单接口,前端传了商品ID和价格,如果不对价格做签名,攻击者完全可以抓包改掉价格再提交。服务端拿到签名后会校验参数是否被改过,这就是为什么签名参数(sign)通常是把所有业务字段拼接后在特定规则下做哈希运算。

第二个目的是增加自动化采集的成本。同样的接口,浏览器直接访问没问题,但脱离这个环境,请求头里少了一个或几个动态变化的字段,服务端一比对就识破了。这种加密未必多复杂,但确实能把很多半吊子脚本挡在外面。

第三个原因则偏合规和审计。一些金融、政企系统要求数据传输过程全程可追踪,所以前端落在请求里的参数必须是密文,服务端留存的日志里也不会出现明文敏感字段。

理解这些目的之后再去看JS代码,你会发现加密算法的选型是有迹可循的。防篡改往往用MD5/SHA摘要,敏感数据传输用AES对称加密或RSA非对称加密,而“防机器人”的往往是把好几个算法揉在一起再套一层Base64。有了这层预判,再翻代码就会有的放矢。

2. 定位加密入口:一套稳定的方法论

加密入口定位是整个JS逆向里最耗时也最考验耐心的环节。很多人卡在这里,不是能力不行,而是没有一套稳定的搜索和调试方法。下面这套流程是我反复验证后总结的,按顺序来基本不会走偏。

2.1 从数据流入手:先抓包后定位

拿到一个目标网站,不要急着去看JS源码。第一步永远是打开浏览器的开发者工具,切到Network面板,勾选Fetch/XHR,然后正常触发一个需要分析的操作,比如登录、搜索、翻页。

找到关键请求后,仔细看Payload和请求头。加密参数通常出现在这几个位置:

  • 请求体(Request Payload)里的某个字段,比如pwd、sign、data、params
  • 查询参数(Query String Parameters),比如?token=xxx&sign=yyy
  • 自定义请求头,比如Authorization、X-Sign、X-Token

这一步的目的不是立刻定位,而是建立一个“参照系”——你先知道最终发给服务器的密文长什么样,后面所有分析和验证都围绕这个密文展开。

个人习惯:我会在Network面板里右键这个请求,选择Copy as cURL,保存到一个临时笔记里。这样哪怕页面刷新了,我也能随时知道原始请求长什么样,不至于调着调着忘了初始状态。

2.2 全局搜索关键词,快速缩小范围

接下来打开Sources面板,按Ctrl+Shift+F全局搜索。不要直接搜密文本身,因为密文是运行时生成的,源码里不可能存在。正确做法是搜索参数名,比如刚才看到请求体里有个pwd字段,那就搜“pwd”。

如果参数名太通用,搜索结果会非常多。这时候换思路,搜一些加密函数常见的特征关键词:encrypt、decrypt、sign、token、secret、md5、sha、aes、rsa、cipher、key、iv。搜到可疑的函数后,点进对应的JS文件,搜索这个函数的定义位置和调用位置。

还有一种常见情况是参数名在源码里被拼接而成,比如上面的案例中pwd实际上是“p”+“wd”。这时候直接模糊搜索“wd”或者“pwd”的一部分,可能更快。遇到压缩混淆过的代码,优先搜索特征字符串,比如类库名、算法名、常量值。

2.3 用XHR断点拿调用栈

如果全局搜索定位效率太低,或者碰上了混淆严重的代码,可以直接用XHR断点。具体操作是:在Sources面板右侧的XHR/fetch Breakpoints里,点加号添加一个URL片段(比如/api/login),然后重新触发请求。

请求发出前调试器会自动停在发请求的那一行JS代码上,这时候看右侧的Call Stack调用栈,逐层往上回溯。每一层都会显示对应的函数名或变量,加密逻辑就藏在这些函数里。

这一步是我在实际操作中使用频率最高的一种方式,因为它能直接“从终点倒推起点”。顺着调用栈往回走,很快就能看到一个函数输出一串密文,然后把它赋值给某个请求字段。那个函数,就是你的主攻目标。

3. 核心细节:常见加解密算法的识别与还原

定位到了函数之后,下一步就是把算法看明白。很多开发者对算法本身并不陌生,但在JS代码里看到各种函数调用时经常反应不过来,尤其是当代码做过变量重命名和函数封装之后。这一节我把最常见的几种算法识别方法和还原思路展开讲。

3.1 一看便知的哈希与Base64

先说最简单的。如果密文是32位十六进制字符串,基本就是MD5;40位就是SHA1;64位就是SHA256。JS里实现哈希时通常引用CryptoJS库,代码大概长这样:

var md5 = CryptoJS.MD5(str).toString(); var sha1 = CryptoJS.SHA1(str).toString(); var sha256 = CryptoJS.SHA256(str).toString();

这类算法不可逆,没法直接还原明文,但如果你要用它拼接参数,只需要在本地用相同的算法和原文跑一遍即可。关键难点在于搞清楚被哈希的原文是什么拼接格式,比如时间戳、随机数、其它参数按什么顺序连接。这就要回到调用处去看那行函数入参。

Base64也一样,源码里看到btoa、Base64.encode或者CryptoJS.enc.Base64.stringify,就是Base64编码。Base64看着像密文,实际上是可逆的,在浏览器控制台直接调用atob("密文")就能解码。遇到这类题属于送分题,别花太多时间。

3.2 AES的四大要素:模式、填充、密钥、IV

AES是实战中最常见的对称加密算法。之所以排第一,是因为它加密效率高,适合敏感数据传输,而且JS生态里CryptoJS用得极其广泛。识别AES不难,CryptoJS.AES.encrypt或者aes.js文件出现时基本可以确定。

难点在于AES有四个核心要素,缺一个都对不上结果:

  • 加密模式:CBC最常用,ECB也有,还有CFB、OFB、CTR等
  • 填充方式:因为AES是分组加密,明文长度必须对齐16字节倍数,常见的是Pkcs7(即Pkcs5)
  • 密钥(Key):16/24/32字节,对应AES-128/192/256
  • 偏移量(IV):CBC模式下需要,ECB不需要

一段典型的CBC加密代码长这样:

var key = CryptoJS.enc.Utf8.parse("0123456789abcdef"); var iv = CryptoJS.enc.Utf8.parse("abcdef0123456789"); var encrypted = CryptoJS.AES.encrypt(plainText, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).toString();

注意这里的key和iv都经过了Utf8.parse处理,说明密钥是字符串直接转字节。有些实现用Hex.parse或Base64.parse,这都会影响最终结果。

还原思路:把这段代码复制到浏览器Console里,手动执行AES.encrypt,输入一个测试明文,看输出是否和抓包里的密文一致。一致就说明你找对了。然后用同样的逻辑在Node.js或者Python里实现,密钥、IV、模式和填充方式保持一致,就能在本地生成合法请求参数。

3.3 RSA的经典玩法:公钥内嵌与私钥还原

RSA在JS里同样常见,尤其是登录密码加密场景。识别特征是出现JSEncrypt这个库,代码里通常有:

var encryptor = new JSEncrypt(); encryptor.setPublicKey(publicKey); var encrypted = encryptor.encrypt(password);

publicKey是一段PEM格式的公钥字符串,以“-----BEGIN PUBLIC KEY-----”开头。RSA是公钥加密、私钥解密,所以如果你想反向解读密文拿到明文,必须得有私钥。爬虫场景下一般不需要反向解密,你只需要用同样的公钥对同样的明文做加密,得到与浏览器一致的密文,就能通过服务端校验。

核心数字:RSA加密时有一个关键点是公钥里的模数n和指数e。如果你在代码里看到一串很长的十六进制数字,比如“00c1...”,那很可能就是n。实操中,直接把包含公钥的那段代码整体拿下来,在Node.js里用jsencrypt模块加载公钥然后加密,比手动还原数字更省事。

3.4 富文本和自定义加密:从结果反推过程

最难缠的是自定义加密,常见于有专门风控团队的平台。密文可能是一长串随机大小写和数字的组合,看不出任何标准算法特征。这类项目没有捷径,只能硬着头皮断点跟读。

我的做法是三步走:

  1. 找到最终输出密文的那一行,打断点
  2. 逐步执行(Step into),观察每一步对数据的变换
  3. 把每一步变换记录下来,翻译成能读懂的伪代码

举个例子,我之前遇到过一个签名算法,外部看是64位十六进制,以为就是SHA256。跟进去才发现它内部对这个64位字符串又做了Base64编码,再去掉前8位,最后又补上了两个固定字符。这种“套娃”操作光靠猜是猜不出来的,必须断点看,逐个环节还原。遇到这种情况,最忌讳的就是浮躁,老老实实记录每一步,最终一定能还原。

4. 实操演示:一个完整参数的还原过程

理论说得再多,不如亲手走一遍。这一节我用一个虚拟的登录场景,完整演示从抓包到定位再到还原的整个流程。场景设定是:登录接口/login,请求体里有username和password,其中password是一段32位十六进制密文。

4.1 建立问题域

打开浏览器登录页,输入任意账号密码,抓包看到:

POST /api/login HTTP/1.1 Content-Type: application/json {"username":"test_user","password":"e10adc3949ba59abbe56e057f20f883e"}

password是32位十六进制,初步判断是MD5或类似哈希。为了验证,我手动把“123456”拿去做MD5哈希,得到的结果正好是e10adc3949ba59abbe56e057f20f883e。那么第一个方案就成立了:这个网站对密码做了MD5摘要。但要注意,很多网站在MD5之前还会加盐(salt),比如md5(md5(password) + timestamp)。所以不能急着下结论,还得看完整逻辑。

4.2 在源码中定位密码被加工的位置

打开Sources面板,全局搜索“password”。在某个函数里看到这样一行代码:

var encryptedPwd = md5($("#password").val());

这就说明密码确实是被MD5后提交的。但为了防止遗漏更多变换,我决定在md5这一行打断点,重新点击登录,观察函数调用栈。好在栈里只有两层,最外层是一个登录事件处理器,没有额外加盐逻辑。此时可以确认:后端收到的password就是明文密码的MD5值。

4.3 在Console里验证

为了确保万无一失,我在Console里手工执行:

md5("123456") === "e10adc3949ba59abbe56e057f20f883e" // true

输出为true,证明定位无误。到这里,这个参数的逆向就完成了——只需要把待提交的密码用MD5哈希后拼进JSON,就能通过服务器校验。

4.4 把加密逻辑整理成独立代码

最后一步是把算法落地成工程代码。由于这里用到的只是MD5,Python的hashlib可以直接处理:

import hashlib password = "123456" encrypted_pwd = hashlib.md5(password.encode('utf-8')).hexdigest()

如果场景里的加密逻辑复杂,比如AES或RSA,我更推荐把扣下来的JS函数原封不动放在Node.js环境中调用,然后用Python的subprocess或Node.js的HTTP接口去对接。这样既保留了原始实现,又避免了重写算法带来的差异问题。

5. 工具与工程化:把逆向结果变成生产力

定位到算法、验证通过之后,距离真正稳定运行还差一步——如何把逆向出来的加密逻辑嵌入到自己的工程里,并且尽量降低后续维护成本。这一节讲工具选型、环境适配和稳定运行的技巧。

5.1 常用工具链汇总

我的日常逆向工作台分成五个部分,每一部分都有明确用途:

工具定位核心用途
Chrome DevTools浏览器调试打断点、搜代码、看调用栈、Console验证
Fiddler4 / Charles抓包代理查看HTTPS请求/响应,适合移动端或非浏览器场景
whistle抓包+改包本地规则注入、mock响应、JS替换
Overrides本地代码替换把线上JS映射到本地文件,方便修改调试
Node.js本地运行环境运行扣下来的JS加密逻辑,生成合法参数

Chrome DevTools的Overrides功能特别值得一说。操作很简单:在Sources面板右键任意JS文件,选Override Content,选择一个本地文件夹后,线上JS就会被本地文件接管。之后你可以在本地自由修改代码、加console.log、甚至直接替换加密函数。这个功能在调试复杂加密时非常好用,不用反复在线上代码里找位置。

5.2 用Node.js做加密逻辑的本地化

很多逆向文章会教你把扣下来的JS代码精简成几行,然后翻译成Python。这个思路在算法简单时可行,算法复杂时其实效率很低,而且容易出错。我的经验是:能跑原版就尽量跑原版

具体做法是:从浏览器里把包含加密逻辑的那段JS函数完整复制出来,保存到一个独立的js文件里,然后在Node.js中调用。如果这个函数使用了window、document、navigator等浏览器对象,需要做最小化的mock:

// mock最小浏览器环境 global.window = global; global.navigator = { userAgent: 'Mozilla/5.0' }; global.document = { cookie: '', getElementById: function() { return { value: '' }; } }; // 引入目标JS文件 const cryptoFuncs = require('./target_crypto.js');

然后再用导出函数的方式生成参数:

const encrypted = cryptoFuncs.getEncryptedPwd('123456'); console.log(encrypted);

这样做的优势是,一旦网站加密逻辑升级,你只需要同步更新JS文件,无需重写算法代码。当然缺点是多了一层Node.js进程的调用开销,但只要控制好频率,完全在可接受范围内。

5.3 调试提速技巧:Hook和验证

再说一个能大幅提速的技巧——Hook。Hook的本质是提前“劫持”目标函数的执行,在函数运行前后插入你自己的逻辑。比如你知道某网站的加密函数叫makeSign,你可以在页面加载后执行下面的代码:

var originalMakeSign = window.makeSign; window.makeSign = function() { console.log(arguments); var result = originalMakeSign.apply(this, arguments); console.log(result); return result; };

这样每次调用makeSign时,入参和出参都会打印到控制台,你不需要打断点反复调试,就能在短时间内拿到一组组输入输出样本。这对后续在本地还原算法、验证算法正确性非常有帮助。

另一个实用的技巧是“控制变量法”:手动修改一个参数,观察密文变化。如果密文变化范围只出现在某一段,说明这个参数只参与了部分运算;如果密文整体面目全非,说明参数参与了首轮变换。这类观察能帮你快速定位被哈希/加密的原始字段。

6. 常见问题与排查技巧实录

最后这部分是我这些年被问得最多的问题,每一个都是真实踩坑记录。我把它整理成一个速查表,你遇到类似情况时可以直接对照排查。

6.1 加密入口找不到怎么办

全局搜参数名搜不到、搜特征词也搜不到,这种情况通常有三个可能:参数名被动态拼接;加密代码被隐藏到了Web Worker或者跨域JS文件里;代码经过了变量名混淆。

我的排查顺序是:

  1. 先搜参数名的一部分,比如签名是cksign,直接搜“cksign”和“sign”都试一遍
  2. 确认是否有Service Worker或Worker线程在后台请求
  3. 用XHR断点拿到调用栈,直接回溯,不依赖关键词搜索
  4. 如果Stack里出现大量匿名函数,说明有混淆,优先看当前作用域里的函数引用

6.2 算法还原后签名不匹配

签名不匹配是所有环节里最容易让人崩溃的。一旦本地生成的密文和浏览器的对不上,按优先级从高到低检查这几项:

检查项说明
编码方式明文字符串是UTF-8、GBK还是Base64编码?JS里通常默认UTF-8
密钥和IV是否经过了Hex.parse或Utf8.parse的转换?
模式与填充使用的是CBC还是ECB?填充是Pkcs7还是ZeroPadding?
数据顺序多个字段拼接时的顺序是否和线上完全一致?
动态参数是否包含时间戳、nonce随机数?本地环境时间是否准确?

我在实际项目中最常栽的跟头就是动态参数——函数内部偷偷调用new Date().getTime()生成时间戳并参与加密。本地测试时,这个时间戳和请求发出的时间如果相差超过允许窗口,就会签名失败。解决办法是让本地代码与线上代码保持“同一个环境变量”,比如统一使用当前时间戳,避免用固定值。

6.3 代码被混淆了怎么办

现在很多站点的JS都做了压缩混淆,函数名、变量名全是a、b、c,阅读难度极高。面对这种情况,不要试图完全看懂每一行,而是抓住一条主线:输入是什么,输出是什么,中间经历了哪几步变换

先用浏览器自带的漂亮打印(Pretty print)把压缩代码格式化,再用局部变量动态观察法:在怀疑的代码位置打断点,然后逐条执行,观察每个变量的变化。只要确定了输入输出,即使中间逻辑看不懂,你也能通过“黑盒复刻”的方式,把整段函数抽出来直接调用。

6.4 有风控和加密壳怎么办

高阶网站会在加密逻辑之上再加一层环境校验,比如检测当前是否在浏览器环境、是否使用了自动化工具。这类校验一旦触发,返回的密文本身就可能是一个诱饵,或者请求直接失败。

我的态度是:这类场景千万不要硬碰硬。单纯破解风控本身是一个无底洞,而且容易触碰合规红线。正确做法是优先通过官方API、合法授权或者业务合作渠道获取数据。如果只是技术研究,建议在授权的靶场环境或自己搭建的测试站上验证方案,而不是拿真实业务系统练手。逆向的核心是理解原理,不是突破防线。


折腾JS逆向这几年,我最大的一个体会是:加密防不住真正想研究的人,但它能把一大批投机取巧的人挡在门外。所以我自己做逆向时,越来越强调“先分析再动手”的流程——从抓包到定位,从识别算法到还原逻辑,每一步都尽量理清楚再进行下一步。这个习惯能帮你省下大量返工时间。

另外,想给初学者一个实在的建议:不要一上来就挑战高难度混淆站点,先从简单的MD5加盐、AES加密这样的项目练手,把控制台调试、全局搜索、XHR断点这些基本功练熟。等这些操作形成肌肉记忆了,再面对复杂参数时就不会慌。说到底,JS逆向的核心不是“破解”,而是“读懂另一段代码的思路”——理解了这一点,参数加解密的大门才算真正向你敞开。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 12:41:12

10 分钟跑通一次 UVR5 人声提取:免费开源的伴奏分离实操笔记

10 分钟跑通一次 UVR5 人声提取&#xff1a;免费开源的伴奏分离实操笔记 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-based-Voice-C…

作者头像 李华
网站建设 2026/9/19 12:39:33

雪亮工程整体解决方案:从三级组网到GB/T 28181接入与验收

简介&#xff1a;雪亮工程整体解决方案PPT面向公安、综治、政府机关、金融与厂矿企业等领域的项目规划与方案设计人员&#xff0c;聚焦公共安全视频监控建设联网应用的“四全”目标&#xff0c;适用于农村平安乡村、城区技防、行业视频整合等场景。内容从政策背景与典型建设模式…

作者头像 李华
网站建设 2026/9/19 12:37:26

SpringBoot+MyBatis+MySQL校园志愿者管理系统实战解析

简介&#xff1a;这是一份可用于毕业设计参考的校园志愿者管理系统论文文档&#xff0c;适合计算机相关专业学生完成Java/SpringBoot方向课程设计或毕业论文时使用。资源按标准论文格式组织&#xff0c;包含摘要、目录、绪论、相关技术介绍等章节&#xff0c;基于SpringBoot、M…

作者头像 李华
网站建设 2026/9/19 12:37:25

E-ZKEco pro中间表对接实战:考勤数据同步全流程解析

简介&#xff1a;这是中控智慧 E-ZKEco Pro 考勤管理平台中间表对接的官方说明书&#xff0c;面向需要将考勤数据与第三方业务系统&#xff08;如 OA、ERP&#xff09;打通的实施工程师、开发人员及运维人员。内容先从系统选项中的数据对接设置讲起&#xff0c;说明按时间点同步…

作者头像 李华
网站建设 2026/9/19 12:35:57

ad986ad经常使用的值

目录其他值装机软件开发工具资源编辑工具信息C# 从字符串获取时间应对 dns 劫持远程桌面连接其他值 护眼背景色&#xff1a; RGB 223&#xff0c;199&#xff0c;155 #DFC79B 标题 RGB 86, 74, 41 #564A29 数据文件夹&#xff1a;Default(链接UserId)、UserId、Common 装机软…

作者头像 李华