干了 5 年逆向,头一回被一个站点的反爬机制恶心到。倒不是说它用了多复杂的 AES、RSA,也不是说动态 Cookie 有多难解,而是整个分析过程里,前面两个小时完全在无效翻代码。后来冷静下来,重新抓包、重新定位、重新理调用栈,才把问题拆开。这篇文章就把这套思路完整复盘一遍。先说清楚,这不是一篇“教你绕过某个网站”的教程,更不是“去爬某某资源站”的教程。真正有价值的,是你在授权范围内做 JS 逆向时,怎么快速定位加密参数、怎么判断动态 Cookie 生成逻辑、怎么从一段混淆代码里找到入口。没有授权的情况下,再简单的站点也不建议碰。想练手,优先选自己的测试站点、公司授权项目,或者公开的 CTF 靶场。
1. 先想清楚,这次“逆向”到底在做什么
1.1 很多人理解的 JS 逆向和实际干的事不一样
一说 JS 逆向,很多人第一反应是:把网站登录密码解密、把接口签名破解、把动态 Cookie 模拟出来。这确实算一部分,但更准确的说法是:理解一个 Web 前端在请求接口之前,到底对哪些数据做了处理,以及这些处理逻辑能不能被还原成可控参数。
我这次遇到的反爬,问题就出在一个chameleon相关的 JS 文件上。一开始我以为只要找到这个文件,把里面的函数复制出来就能跑。结果发现根本不行,因为这个 JS 不是一个纯函数模块,它会在页面加载过程中读取环境信息、浏览器指纹、时间戳,甚至上一个接口返回的临时状态。也就是说,你光看文件内容,根本看不出它最终生成了什么。
这个认知很重要。它决定了你接下来的动作是“照着代码猜”还是“跟着请求链路找”。
1.2 合规边界一句话:有没有权限
在做任何分析之前,先问自己一个问题:这个站点,我有没有权限测?
有权限的情况包括:
- 自己开发或自己负责的网站;
- 公司明确授权的安全测试项目;
- 公开的 CTF 靶场、安全训练平台;
- 自己搭建的本地测试环境。
没有权限的情况,例如:
- 没有授权的第三方站点;
- 明确禁止爬取或测试的站点;
- 内容来源本身就有争议的站点。
这个不是套话。JS 逆向和爬虫反爬的很多技术本身是双刃剑,写出来的文章如果被拿去对付别人的业务系统,风险很大。所以我后面所有步骤,都默认你是在授权环境里做测试。
2. 一个加密接口的常规分析路径
2.1 抓包阶段:不要只盯着响应数据
很多人一打开浏览器 F12,就先看响应 JSON,然后抱怨“为什么这个接口返回没有数据”。实际上真正的麻烦在请求阶段。
我这次遇到的接口,请求 URL 本身不带特殊参数,但请求头里多了一个X-Sign,每次请求都不一样。同时 Cookie 里还有一个动态值,第一次请求是空,第二次请求才开始出现。如果只盯着响应数据,永远看不明白。
正确做法是先把请求链路完整记录出来。以 Chrome DevTools 为例,建议关注四类信息:
- 请求 URL 和查询参数;
- 请求头,尤其是自定义 Header;
- Cookie 的变化过程;
- 请求触发顺序。
我会先做一张简单的表格,把每一次请求的地址、时间、关键参数、返回状态都记下来。很多时候反爬不是单点加密,而是多个请求之间互相配合。前面一次请求生成的临时值,后面一次请求要用到;你如果只分析最后一个接口,就会缺上下文。
2.2 定位可疑 JS:全局搜索和关键字过滤
抓包确认了加密参数之后,下一步是找到生成这些参数的 JS 代码。最直接的方法不是看文件树,而是用全局搜索。
以X-Sign为例,我会先在 Sources 面板里搜索X-Sign、sign、headers、cookie这些关键词。搜索结果里如果出现 JS 文件,再点进去看上下文。
常见的几个搜索入口:
- 搜索参数名本身,比如
X-Sign; - 搜索常见算法关键字,比如
md5、sha256、AES、RSA、Base64; - 搜索赋值语句,比如
setHeader、setCookie、document.cookie; - 搜索可疑变量名,比如
token、signature、chameleon。
如果代码量特别大,还可以用全局搜索正则。比如在命令行或者编辑器里搜索:
grep -rn "X-Sign\|signature\|chameleon" ./static/js/这个阶段的目标不是马上搞懂算法,而是先把可疑代码的“片区”圈出来。就像排查漏水一样,先确定是哪几面墙有问题,再砸墙。
2.3 断点调试:从哪里下断点最省时间
找到可疑代码后,不要从头到尾读一遍。先从可疑代码的入口下断点,然后重新触发一次请求。这样能看到函数执行前的输入、执行过程中的变量变化、执行后的输出。
我自己的习惯是在三个位置下断点:
- 参数拼接处:比如
headers['X-Sign'] = xxx; - 加密函数入口:比如
function getSign(params); - Cookie 赋值处:比如
document.cookie = ...。
如果只看返回值,不知道中间过程,很容易被混淆代码带偏。断点之后,重点看三块内容:
- 入参是什么;
- 经过哪些函数;
- 出参和请求参数是否一致。
有些 JS 会把字符串拆成十几个变量,再用数组下标重组。这时候可以直接在控制台把入参和出参打印出来,对比最终值,不用每一步都看懂。
2.4 调用栈回溯:找到加密函数的最直接方法
如果断点落在了一个很靠后的函数里,比如已经计算出X-Sign的值,但你想知道是谁调用了它,这时候就要看 Call Stack。
调用栈会把当前函数的调用链从下到上展示出来。你沿着调用链往上点,就能看到完整的处理流程:哪个函数先取了时间戳,哪个函数把时间戳和某个固定字符串拼接,哪个函数做了 MD5,最后又是谁把结果写进了请求头。
这一步最重要的作用是识别“无意义干扰”。很多反爬 JS 会故意加一堆没用的分支、死代码、陷阱函数。如果你只在某一个函数里打转,很容易陷进去。调用栈能帮你快速跳出迷魂阵。
还有一个小技巧:当发现一个重要变量在某一段代码里被赋值,但代码被混淆得很厉害时,可以用开发者工具里的Object.defineProperty对变量做监听,或者在控制台重新定义这个变量的 setter。这是分析混淆代码的常用手法,但只在你有权测试的站点上用。
3. 动态 Cookie、签名参数和时间戳,常见干扰项
3.1 动态 Cookie:先看生成时机,再看是否依赖前置请求
这次最让我头疼的是动态 Cookie,也就是很多俗称的“动态 cookie 反爬”。它最恶心的地方在于:你抓包时 Cookie 是正常的,但一旦脱离真实页面环境,Cookie 就失效了。
分析动态 Cookie 时,我一般按这个顺序排查:
- 先看 Cookie 名称是什么,比如
_m、_token、traceid; - 在 JS 里搜索这个 Cookie 名称,找到赋值位置;
- 看赋值位置是在页面加载阶段,还是在某个接口返回之后;
- 如果赋值依赖接口返回,就要看前置接口的返回数据;
- 如果赋值依赖 JS 运行环境,就要看它是否校验了浏览器特征。
我这次发现,那个chameleon相关 JS 会在页面加载时读取 Canvas 指纹、时区、语言、WebGL 信息,再把它们一起拼进一个字符串,生成一个 Cookie。这个 Cookie 不是一次性的,但它的有效期很短,而且一旦你的请求头和正常浏览器不一致,服务器就会判定异常。
所以分析动态 Cookie 的关键不是破解算法本身,而是搞清楚“它依赖了哪些环境变量”。环境变量越难伪造,越说明这是一个前端行为检测型反爬,而不是单纯的加密参数。
3.2 签名参数:不是所有加密都需要破解
很多接口里会有sign、signature、token之类的参数。遇到它们时,先不要急着还原算法,先判断这个参数是“服务端签发的凭据”,还是“前端根据请求参数现场计算的签名”。
举个例子:
- 如果
sign是从上一个接口的响应里拿到的,那它就是服务端凭据,不需要破解,只需要正常维护租约; - 如果
sign是前端根据当前请求的时间戳、路径、请求体重新算出来的,那才是需要分析的签名算法; - 如果
sign是在页面加载时生成、之后每次请求都用同一个值,那它可能只是环境校验码,不是请求级签名。
判断方式很简单:刷新页面,不发起目标请求,看这个值是否已经存在;再发一次目标请求,看这个值是否变化。如果固定不变,很可能是一次性环境凭据;如果每次请求都变,那就是请求级签名。
3.3 时间戳和随机数:判断可预测性
时间戳是反爬分析里最常见也最好入手的地方。很多 JS 会用Date.now()或new Date().getTime()作为加密因子。你用断点停在加密函数入口,看入参里有没有当前时间戳,再看函数内部是否调用了时间相关 API。
但要注意,有些站点会故意把时间戳改成“从服务器返回的时间”,而不是本地时间。如果本地时间被改了,签名就变了。这时候不能只看本地时间,要找到服务器时间从哪来。
随机数则要分两种情况:
- 真随机数:受环境熵影响,每次不一样,分析难度高;
- 伪随机数:由固定种子生成,只要种子和算法一致,可以预测。
识别方法是在控制台连续执行几次生成逻辑,看结果是否有规律。如果同一个页面里多次出现的随机数看起来完全独立,那很可能是真随机。如果是根据某个时间种子生成,那就能通过种子复现。
3.4 常见报错和排查链路
分析过程中最烦的不是“看不懂”,而是“看着没问题,但一验证就失败”。我总结了一套排查链路,遇到问题先按这个顺序走:
- 先看请求有没有真正发出去,是不是被浏览器拦截了;
- 再看请求头和 Cookie 是否完整,有没有漏掉动态值;
- 然后看参数里的时间戳和随机数是否和当前请求匹配;
- 接着看签名算法是否依赖了某个环境变量,比如 Canvas 指纹、WebGL 信息;
- 最后看服务的返回状态码和错误信息,判断是签名错误、Cookie 过期还是行为检测。
这里最容易忽略的是“环境变量”。你可能把一个函数完整还原了,但因为它读取的是页面里的隐藏输入框值,而你的脚本里没有这个输入框,所以结果始终不对。遇到这种情况,先回页面里看看那些隐藏输入框、data 属性、meta 标签,很多时候答案就在那儿。
4. 分析完之后,怎么反哺防护策略
4.1 从攻击者视角看前端防护
做 JS 逆向分析,最终不一定是为了写脚本。对于业务开发和安全防护人员来说,理解攻击者怎么拆你的前端,是提升防护能力的重要一步。
我这次做完分析后,最大的感受是:大多数前端加密,防的不是“真正的攻击者”,而是“自动化脚本”。它真正发挥作用的场景,是提高批量调用的门槛,让普通脚本跑不起来。但攻击者只要有足够的耐心,把所有环境校验都模拟出来,最终还是能跑通。
所以不要指望某一个反爬手段能解决所有问题。更合理的思路是把前端加密、行为检测、服务端风控和频率限制组合起来。
4.2 更推荐的前端加固方向
如果你是在给自己站点做防护,有几个方向比单纯堆加密更有效:
- 加密参数里一定要绑定“请求上下文”,包括当前会话、时间戳、请求路径,避免别人只拿一个函数就能算出所有请求的签名;
- 敏感逻辑不要全放在一个 JS 文件里,可以拆分模块,增加定位成本;
- 动态 Cookie 要设置有效期,并且要绑定环境指纹,防止长期复用;
- 服务端要对参数做二次校验,不能只验证签名格式,还要验证签名是否过期、是否重复使用;
- 加强对异常频率的识别,比如同一 IP、同一 Session、同一浏览器指纹在短时间内大量请求。
这几点不复杂,但能把分析成本从“半小时”提高到“半天”。对大部分普通流量来说,这个成本已经足够劝退。
4.3 不要迷信某一种反爬
还有人喜欢问:动态 Cookie 是不是比签名参数更厉害?不是。所有前端逻辑都是跑在用户浏览器里的,攻击者只要能打开 DevTools,就一定能通过断点看到执行过程。前端反爬只有“成本高低”的差别,没有“无法破解”的绝对安全。
真正稳的防线,一定有一部分在服务端。前端负责把请求做得“像真人”,服务端负责判断“这个请求是否可信”。两者结合,才能形成有效的防护体系。
5. 复盘:真正让人崩溃的不是反爬,而是没有排查顺序
5.1 我的完整排查顺序
这次被那个chameleon相关 JS 恶心到之后,我给自己定了一个标准流程。后面再遇到类似问题,都按这个顺序走,效率高很多:
- 复现请求:找一个稳定能触发加密请求的操作,保证每次抓包结果可重复;
- 抓包记录:把请求 URL、Header、Cookie、请求体、响应状态全部记录下来;
- 参数分类:把请求里所有动态参数分成“服务端下发”“前端计算”“环境生成”三类;
- 全局定位:搜索参数名、算法关键字、赋值语句,找到可疑 JS 文件;
- 断点分析:在参数拼接、加密函数入口、Cookie 赋值处下断点;
- 调用栈回追:从执行结果往回找调用链,找出真正的加密过程;
- 小范围验证:用最小脚本在本地验证单个函数输出,能通过后再做请求级测试;
- 记录边界:把哪些参数依赖环境、哪些依赖前置请求、哪些有效期很短都记下来。
这套流程不一定保证每个站点都能快速搞定,但能避免“乱翻代码两小时,最后一无所获”的局面。
5.2 工具链建议
做这类分析,浏览器自带的 DevTools 其实已经够用。如果遇到更复杂的混淆,再考虑其他工具。
我常用的配置很轻量:
- Chrome DevTools:断点、调用栈、全局搜索、Network 面板;
- Fiddler 或 Charles:抓移动端或跨端请求;
- Python + requests/httpx:用来写本地验证脚本;
- VS Code:用来整理分析结果和写正则搜索;
- Node.js:用来单独运行前端算法片段,验证函数输出。
不建议一开始就上很重的自动化框架。先用 DevTools 把一条请求理顺,再进入脚本验证阶段。这个顺序能帮你节省大量排错时间。
5.3 自检清单
最后留下一份自检清单,每次做完一轮分析后对照检查:
- 我是否有权限对这个站点做测试?
- 目标请求的完整参数和触发顺序是否已经记录?
- 动态参数是否都找到了来源,是前置请求、环境指纹还是前端计算?
- 关键函数的入参和出参是否已经验证,而不只是“看懂了”?
- Cookie 和签名是否依赖浏览器环境,脚本脱离页面后是否会失效?
- 时间戳和随机数是否存在可复现的生成逻辑?
- 是否把所有分析过程记录下来了,避免下次重新踩坑?
- 是否已经把分析结果转化成防护建议,而不只是停留在破解层面?
如果你发现自己在某个环节反复卡住,很大概率不是能力问题,而是前面某一步的信息没采集完整。回到抓包那一步,重新记一遍请求链路,往往比继续硬啃混淆代码更有效。这个习惯,比会多少断点技巧都重要。