ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

瑞数加密逆向实战:Cookie生成链路与绕过方案

瑞数加密逆向实战:Cookie生成链路与绕过方案 从页面能打开但数据全是空到真正拿到完整JSON这个排查过程整整耗了我一个周末。如果你也在逆向某个带瑞数加密的公示平台大概率会遇到同样的体验Request Headers 里躺着一个__jsl_clearance_s页面正常访问没问题脚本一跑就是 403连静态HTML都拿不到。先说清楚这篇文章是实战记录不是原理教科书。我会用某海关公示平台作为分析样本把瑞数加密的识别、定位、断点调试、Cookie生成链路拆开讲最后给出几种可落地的执行方案和各自的坑。内容偏JS逆向基础向适合已经会F12、会看调用栈、但第一次正面撞上瑞数的朋友。1. 瑞数加密的防护机制为什么一个Cookie能卡住大批爬虫瑞数和传统的WAF不一样它不靠规则库封IP也不靠简单的验证码拦截。它的核心逻辑是服务器动态下发一段JS浏览器执行这段JS后生成一个动态令牌后续每次请求都要带上这个令牌服务器端验证通过才返回真实数据。1.1 动态令牌的生成链路整个链路可以拆成四步。第一步浏览器首次请求页面时服务器返回的不是真正的HTML而是带有一段加密JS的壳页面。这段JS的URL后缀通常带随机数比如wzws_js_xxx.js实际执行时会动态生成新的JS代码。第二步浏览器执行这段动态JS会进行一堆环境检测Canvas指纹、字体列表、时间戳偏移、浏览器属性等然后根据检测结果计算出Cookie值也就是__jsl_clearance_s。第三步设置了Cookie之后页面自动刷新带上这个Cookie重新请求。第四步服务器验证Cookie。验证通过返回真实内容验证失败继续给你一段新的JS让你再算一次。这个设计很聪明因为每次下发的JS都不同生成的Cookie也不同你就算把某一次的算法逆向出来下一次它又变了。这也是瑞数被叫做动态防护的原因。1.2 它到底在防护什么很多人有个误解觉得瑞数是用来防破解的逆向它的人都是想破解它。其实不是瑞数防的不是破解是自动化。它的核心目标是区分真人操作和脚本请求。真人操作会有鼠标轨迹、键盘事件、页面停留时间等行为特征这些特征会在执行JS的过程中被采集并编码进Cookie。脚本请求没有这些特征环境检测那一关就过不去拿到的Cookie就是无效的。理解了这一点你就知道为什么纯Python模拟请求基本走不通了——因为Cookie的计算依赖浏览器环境。你要么用浏览器环境的JS引擎去执行要么把浏览器环境本身模拟出来没有第三条路。2. 识别判断怎么确认目标是不是瑞数加密在动手之前先学会确认目标。识别瑞数其实不难有四个比较明显的特征。特征一页面会莫名刷新一次。手动用浏览器访问目标站点你会发现页面加载到一半会自动刷新一次。第一次加载的HTML里没有真实数据刷新之后才有。这个刷新就是瑞数在设置Cookie后自动发的。特征二Cookie里有特征字段。打开开发者工具的Network面板刷新页面观察请求的Cookie。如果出现了__jsl_clearance_s基本可以确定是瑞数这个字段是瑞数最典型的标识。特征三JS文件路径带随机数。看Network里的JS请求如果某个JS文件的URL是以.js结尾但前面带一大串随机字符或者动态生成、每次刷新都不一样大概率是瑞数的壳。不同版本的瑞数文件名不一样常见的有wzws_js_*.js、challenge_*.js等。特征四格式化工具基本废掉。你把这堆JS拉到本地用Prettier格式化会发现代码恢复得七七八八但变量名完全是乱码而且代码结构非常诡异——大量的数组索引跳转、字符串拼接、动态函数构造。这就是瑞数对JS代码做的混淆处理。我当时分析的海关公示平台就是典型样本首页HTML窗口期极短想抓包得开Preserve log刷新两次之后才能看到真实接口。如果你打开一个页面发现符合以上两条以上特征就可以锁定瑞数了。3. 断点定位从一个Cookie反推到核心生成函数识别只是开始真正麻烦的是定位。瑞数把核心逻辑藏得比较深上来就搜document.cookie大概率什么都搜不到。我一般有三个步骤。3.1 从触发点反推调用链第一步在Network面板里找到那个带__jsl_clearance_s的Cookie的Set-Cookie请求右键Copy as cURL但这里不是让你用curl访问而是要看这个Cookie是在哪个请求里被种下的。接下来对Cookie的下发点下断。在Sources面板里搜__jsl_clearance_s大概率能搜到一个赋值语句类似document.cookie __jsl_clearance_s t ;Path/;Max-age31536000;在那个t上右键 Add to watch然后刷新页面就能看到这个t是哪儿来的。继续往下追你会发现它是某个函数调用的返回值。这个方法有两个坑一是搜__jsl_clearance_s可能搜出多个结果需要手动排除二是有些版本里字段名被动态拼接光搜这个字符串搜不到。这种情况就换思路搜clearance或者cookie关键字。3.2 直接搜特征字符串锁定核心函数第二个思路更直接——搜特征字符串。瑞数生成的Cookie值里有一段很明显的固定结构一段明文一段密文明文里包含时间戳和随机数格式密文是一长串十六进制无意中会在JS里留下特征。在Sources面板全局搜索Mac 是CmdShiftFWindows 是CtrlShiftF搜Math.floor、Date.now、eval这些关键字往往能快速定位到核心代码段。我当时定位到的核心代码是一个自执行函数里面用了一个二维数组来存储各种字符串子串然后通过不断拼接、反转、base64解码生成真正的逻辑代码。这种混淆方式在瑞数里很常见。3.3 借助调用栈回溯到发起位置断点打在关键赋值处后不用急着看代码内容先看右边的Call Stack。从调用栈从上往下翻能快速理清调用层级。我习惯从最顶层往下数第三到第五层那里通常是核心入口函数。这里有个技巧瑞数的逻辑函数经常是动态生成的你在Sources面板里看到的代码并不是原貌而是执行到一半才被eval出来的。盯住eval这个词只要断点停在eval上就往下一层走那才是真正的核心逻辑所在。4. Cookie结构拆解明文段与密文段到底在表达什么拿到核心逻辑之后先别急着去管代码怎么写的把Cookie本身的结构拆开能省下大量时间。4.1 一个真实的__jsl_clearance_s长什么样以我当时抓到的为例__jsl_clearance_s1717149325.975|0|P%2Bt4GJZkQZvZ%2Bz0j8I0IoIuVz%2BO...|RkRnM2ZoUmpabn...用|分割后是两段半。第一段1717149325.975是生成Cookie时的时间戳精确到毫秒。第二段是0这个值在不同版本里含义略有不同有的是版本号有的是计数器。剩下两段长编码分别是明文加密结果和密文校验结果。关键是服务器会校验时间戳。如果请求进来时时间戳和服务器时间偏差过大或者Cookie生成时间过久比如超过一定分钟数服务器直接拒绝。这就是为什么临时生成一个Cookie去访问不可行秒级时效是硬指标。4.2 核心函数还原的关键步骤拆完结构之后主要工作就是还原那两段加密编码的生成逻辑。这里我给一个通用思路。首先观察动态JS的代码结构。瑞数对代码做了大量数组化处理——字符串都被拆成字符数组再通过索引引用。逆向时第一件事是把这些数组还原为字符串常量。手工做太慢用工具辅助比如在线解码工具或写个简单的正则替换脚本把_0x[0-9a-f]这类索引映射到真实值。其次定位加密函数。搜索AES、DES、base64不太靠谱因为这些词在混淆后基本不存在。正确做法是找f、encrypt等常见命名被混淆后的映射。我的经验是找到一个函数传入一个对象输出一个字符串且入参和出参都经过多轮XOR或位移运算那基本就是加密函数。最后也是最关键的——环境检测校验。瑞数会采集浏览器指纹把这些指纹的运算结果拼进Cookie。你在本地Node环境里执行JS如果环境对不上生成的Cookie就是无效的。具体来说Canvas的toDataURL、navigator.userAgent、screen.width、document.fonts等属性都会被采集成字符串然后做哈希运算拼进密文。4.3 环境指纹的还原策略这就是瑞数逆向里最耗精力的一环。每个版本的瑞数采集的指纹种类不一样你在逆向时逐个对比即可。举几个常见的window.navigator.userAgentwindow.screen.width window.screen.heightnavigator.languages.join(,)document.createElement(canvas).toDataURL()其中Canvas指纹是最难搞的因为不同环境光栅化结果不同。好在信息技术足够成熟你可以在Node环境里用node-canvas补齐。实在补不齐的就上浏览器环境模拟让代码直接跑在真实的浏览器引擎里这样环境指纹天然正确。5. 执行方案的取舍纯Python改写、Node补环境、浏览器RPC到这一步理论上你已经理解了瑞数的完整链路接下来要选一种执行方式落地。我列一下我这边的测试对比方便你按自己的情况选。方案实现成本稳定性反检测强度适用场景纯Python模拟执行JS高需要改写全部算法低低环境指纹难对齐几乎不推荐Node.js jsdom 补环境中本质是把混淆JS拉进Node执行中中依赖补环境完整度接口不多、个人学习浏览器RPC调用真实浏览器执行低高高指纹天然正确项目成形、稳定采集无头浏览器直接访问最低高高但会拉高资源占用数据量小、重效率5.1 纯Python模拟为什么不推荐有的朋友习惯用Python的execjs库来执行任意JS但瑞数的JS混淆程度太高不是不能执行而是每次下发的代码都不一样你没法把代码写死。就算用execjs动态执行新下发的JS环境指纹那一关依然过不了。Node里还能靠补环境解决Python里补起来更痛苦——你需要在Python里手动设置一堆全局变量、属性和方法工作量不比重写一遍算法小哪去。5.2 Node.js补环境的完整思路这是纯技术流选手比较偏爱的方案。基本思路是把瑞数下发的JS代码拿过来放到Node.js环境里执行同时把缺失的浏览器API一一补上。我当时用jsdom做基础DOM模拟然后手动补齐了这么几类东西// 用 Node 模拟 window 对象的常用属性 global.window new JSDOM(!DOCTYPE htmlhtmlbody/body/html, { url: https://目标站点地址, referrer: https://目标站点地址/, userAgent: Mozilla/5.0 ... }).window; // 补齐 canvas 指纹相关 const canvas require(canvas); global.document.createElement function(tag) { if (tag canvas) { return canvas.createCanvas(300, 150); } return new JSDOM().window.document.createElement(tag); };这里有个坑特别提醒canvas库的渲染结果和真实浏览器有差异如果对方采集的是canvas.toDataURL()你会发现补出来的结果是错的。我的解决办法是固定返回一段预先计算好的哈希值因为目标站点最在意的是这个值而不是真的图像内容。jsdom本身也有坑它并不完全支持window.Window、window.Document等属性。所以我补环境时做了一些改写if (!(global.window instanceof Object.getPrototypeOf(global.window).constructor)) { // 修正原型链 }5.3 浏览器RPC方案投入产出比最高的稳定方案如果你做的是长期项目而不是一次性分析我建议直接上浏览器RPC。核心思路不逆向JS直接控制一个真实的浏览器实例让它完成Cookie生成和请求然后通过WebSocket把Cookie回调出来。这样你既可以在脚本侧用Python写业务逻辑又能让浏览器负责最麻烦的加密计算。我当时的做法是写了一个Payload脚本注入到浏览器页面里var ws new WebSocket(ws://127.0.0.1:6789); ws.onopen function() { ws.send(JSON.stringify({ action: get_cookie, value: document.cookie })); };然后在Python侧开一个WebSocket服务端等浏览器主动上报拿到Cookie后放进后续请求的Header里。这个过程完全绕开了JS逆向稳定性非常高。代价就是内存占用大、需要常驻浏览器进程。6. 几个容易翻车的细节和合规线这部分聊点实际的坑我踩过之后才明白的。6.1 最容易忽略的坑坑一Cookie有端口绑定。有些版本在生成Cookie时会把当前源信息也算进去。你从本地调试环境拿到的Cookie放到服务器上请求可能直接失效。排查半天环境问题结果是这个。坑二并发请求会导致Cookie失效。我试过拿着同一个Cookie去并发请求多个接口结果其中几个返回403。因为服务器端会校验请求频率和请求上下文高频短时间内的多个请求触发了风控。解决方案要么控制请求间隔建议至少300毫秒要么每个请求都获取新Cookie。坑三Cookie的失效时间比想象中短。__jsl_clearance_s不是永久的实测通常在几十秒到几分钟之间。你拿到Cookie之后别磨蹭立刻发请求否则等Cookie过期了又得重新生成一遍。坑四不要只补Cookie忽略了Headers。有时候你费劲搞定了Cookie发现返回的还不是目标数据。那是因为瑞数会把请求头里的Accept-Language、Sec-Ch-Ua、User-Agent等当成认证因子如果和Cookie生成时的不一致照样拒绝。6.2 合规线再说直白一点做JS逆向是为了技术学习、接口调试和公开数据的合规采集。分析过程可以顺手但别越界。我当时选择分析海关公示平台是因为公示数据本身是向社会公开的做的是信息公开的抓取不是绕过权限去窃取非公开数据。如果你的目标是登录后的用户数据、受保护的个人信息或者打算批量爬取后用于商业变现我建议在动手之前先确认目标是否合规别最后惹上麻烦。学会瑞数的识别和应对思路最大的价值是理解了动态防护这一类系统的设计思路。当前端把逻辑藏在一层层混淆和动态执行背后的时候你能不能顺着蛛丝马迹摸到源头这才是值得练习的能力。最后再提一个小建议分析任何站点之前先把目标站点的 robots 协议和用户协议读一遍这能帮你避免大量不必要的麻烦。
返回列表