
干了 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 和查询参数请求头尤其是自定义 HeaderCookie 的变化过程请求触发顺序。我会先做一张简单的表格把每一次请求的地址、时间、关键参数、返回状态都记下来。很多时候反爬不是单点加密而是多个请求之间互相配合。前面一次请求生成的临时值后面一次请求要用到你如果只分析最后一个接口就会缺上下文。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 和签名是否依赖浏览器环境脚本脱离页面后是否会失效时间戳和随机数是否存在可复现的生成逻辑是否把所有分析过程记录下来了避免下次重新踩坑是否已经把分析结果转化成防护建议而不只是停留在破解层面如果你发现自己在某个环节反复卡住很大概率不是能力问题而是前面某一步的信息没采集完整。回到抓包那一步重新记一遍请求链路往往比继续硬啃混淆代码更有效。这个习惯比会多少断点技巧都重要。