Skip to content

进阶:补环境与反爬对抗

“补环境”是 JS 逆向工程中的核心高级技术,主要用于应对瑞数(RuiShu)、Akamai、F5 等强对抗型反爬系统。其核心逻辑是在 Node.js 等非浏览器环境中,手动模拟出浏览器特有的对象(BOM、DOM)和行为,欺骗服务器端的检测脚本。

1. 核心原理与调试手段

1.1 为什么需要补环境?

浏览器执行 JS 的上下文(window)与 Node.js 执行 JS 的上下文(global)差异巨大。反爬 JS 代码会检查这些差异(如 window.navigator 是否存在,document.cookie 是否可写)来判断当前环境是否为真实浏览器。

1.2 神器:Recursive Proxy (递归代理)

这是补环境最关键的调试工具。通过 Proxy 拦截所有对象属性的读取,我们可以准确知道反爬代码到底检测了什么。

jsx
// 简易递归代理框架,用于捕获缺少的环境
function getProxy(obj, name) {
    return new Proxy(obj, {
        get: function(target, prop) {
            // 排除一些 Node 内部调用的干扰属性
            if (typeof prop === 'symbol' || prop === 'inspect') {
                return target[prop];
            }
            console.log(`[读] ${name}.${String(prop)}`);
            const val = target[prop];
            // 如果属性值是对象,继续递归代理
            if (typeof val === 'object' && val !== null) {
                return getProxy(val, `${name}.${String(prop)}`);
            }
            return val;
        },
        set: function(target, prop, value) {
            console.log(`[写] ${name}.${String(prop)} = ${value}`);
            target[prop] = value;
            return true;
        }
    });
}

// 挂载到 window
window = getProxy({}, "window");

2. BOM (浏览器对象模型) 模拟重点

2.1 Window 与 Global 隔离

  • 循环引用:在浏览器中,window.window === windowwindow.self === window,[window.top](http://window.top) === window (在无 iframe 时)。这必须严格模拟。
  • 变量泄漏:Node.js 中的 global 变量如果不小心泄漏到 JS 执行环境中(例如 process 对象),会立刻暴露身份。务必删除或隐藏 Node 特有变量

2.2 Navigator (身份指纹)

  • webdriver: 高危。自动化工具通常为 true。需设置为 undefinedfalse
  • plugins / mimeTypes: 许多检测会遍历插件长度。如果为空数组 [],评分会降低。
  • platform / userAgent: 必须与 HTTP 请求头完全一致。

2.3 Location (地址栏)

  • 很多加密算法会依赖 location.hreflocation.search 参与哈希计算。如果 location 为空或 URL 不对,生成的 cookie/token 将无效。
  • 模拟时要解析目标 URL 的 protocol, host, pathname, search, hash。

2.4 Screen & Performance

  • Screen: width, height, colorDepth。注意多显示器场景的模拟。
  • Performance: [performance.now](http://performance.now)() 是高频检测点,用于检测脚本执行耗时或检测环境卡顿。

3. DOM (文档对象模型) 模拟重点

3.1 Document 对象

  • Cookie 钩子:必须实现 getter/setter。瑞数等反爬会通过 JS 设置 cookie,然后立刻读取校验。
  • Referrer: 必须与请求头中的 Referer 保持一致。
  • createElement:
    • 反爬脚本常用 div = document.createElement('div') 然后检查 div.innerHTML 默认值,或者 div.appendChild 的行为。
    • 动态创建的元素(如 canvas)也需要具备相应的属性和方法(如 toDataURL)。

3.2 HTML 元素原型链 (Prototype Chain)

检测重灾区

  • 简单模拟:var div = {} (错误,容易被 div instanceof HTMLDivElement 识破)

  • 深度模拟:

    jsx
    // 构造原型链
    var HTMLDivElement = function() {};
    var HTMLElement = function() {};
    HTMLDivElement.prototype = Object.create(HTMLElement.prototype);
    // ... 更多继承
    Object.defineProperty(window, 'HTMLDivElement', { value: HTMLDivElement });

4. 高级对抗:Native 函数伪装 (toString 保护)

反爬脚本会检查核心函数(如 eval, setTimeout, btoa)的 toString() 结果。

  • 检测逻辑window.atob.toString() 应该返回 "function atob() { [native code] }"。如果是 JS 模拟的,通常会返回 JS 源码。
  • Hook 方案
jsx
// 保护 toString 的通用方案
(() => {
    const $toString = Function.prototype.toString;
    const mySocket = 'function() { [native code] }'; // 或者是具体的 name
    
    // Hook Function.prototype.toString
    Function.prototype.toString = function() {
        // 如果当前函数是被我们需要保护的函数,返回 native code
        if (this === window.atob || this === window.setTimeout) { // 示例逻辑
            return `function ${this.name}() { [native code] }`;
        }
        // 否则返回原始结果
        return $toString.call(this);
    };
    
    // 注意:别忘了保护 toString 自身!
    // Function.prototype.toString.toString() 也必须返回 native code
})();

5. 实战案例详解

5.1 瑞数 (RuiShu) - 4/5/6 代区分与逆向

瑞数的核心逻辑是 动态代码 (VMP) + 环境检测

  • 流程:请求首页 -> 返回 HTML (含 <meta><script>) -> 浏览器执行 JS (生成 cookie) -> 携带 Cookie 二次请求。
  • 区分特征
    • 4 代:通常有“二次 Cookie 生成”的过程。第一次生成的 Cookie 是假的(长度较短),JS 会再次生成一个真 Cookie(长度很长),然后刷新页面。
    • 5 代:去掉了“假 Cookie”步骤。直接生成真 Cookie(通常以 FSSBBIl1Uqz 等开头,名称动态)。
    • 6 代:在 5 代基础上加强了 VMP 混淆,增加了更多环境检测点(如 Math.random 随机数序列检测),Hook 难度极大。
  • 逆向思路
    1. 定位入口:Hook document.cookiewindow.eval。瑞数通常通过 eval 执行解密后的 VM 代码。
    2. 扣代码 vs 补环境:瑞数逻辑过于复杂(几万行 VM 调度),硬扣算法(还原 VMP)成本极高。推荐补环境
    3. 固定随机数:瑞数会利用 Math.randomDate.now 参与加密。在 Node.js 中必须重写这两个函数,固定返回值,以便调试时输出一致。
  • 调试代码 (Cookie Hook)
jsx
// Hook Cookie Setter 定位加密位置
(function() {
    'use strict';
    var cookie_cache = document.cookie;
    Object.defineProperty(document, 'cookie', {
        get: function() {
            return cookie_cache;
        },
        set: function(val) {
            console.log('正在设置 Cookie:', val);
            debugger; // 在此处断点,查看调用栈
            cookie_cache = val;
            return val;
        }
    });
})();

5.2 Akamai (2.0/3.0) - 传感器数据

Akamai 的核心是收集传感器数据 (sensor_data),生成 _abck Cookie。

  • 特征:请求中包含 _abck cookie,POST 请求提交巨大的 sensor_data 字符串。
  • 逆向思路
    • 鼠标/键盘轨迹:Akamai 极度依赖用户行为。必须模拟真实的鼠标移动(贝塞尔曲线)、点击间隔和键盘输入。直接复制粘贴的 payload 必挂。
    • 环境一致性navigator 属性必须与 TLS 指纹匹配。
    • 被动检测:Akamai 会检测开发者工具(DevTools)是否打开。
  • 代码片段 (模拟鼠标移动数据)
jsx
// 伪代码:生成贝塞尔曲线轨迹
function generateBezierPath(start, end, steps) {
    // ...计算贝塞尔控制点...
    return path; // [{x:1, y:1, t:100}, {x:2, y:3, t:110}, ...]
}
// sensor_data 中记录的是轨迹的差值编码

5.3 Cloudflare 5秒盾 (Turnstile / IUAM)

Cloudflare 的“5秒盾”本质上是 TLS 指纹校验 + JS 算力挑战 (PoW)

  • 核心痛点
    • TLS 指纹:Python 的 requests 库发出的 TLS 握手包(Client Hello)特征明显,会被 CF 直接拦截(403 Forbidden),甚至不触发 5秒盾 JS。
    • JS Challenge:如果是 Turnstile(类似验证码),需要计算复杂的数学题(PoW)。
  • 解决方案
    1. TLS 层面 (最关键):放弃 requests,使用支持模拟浏览器 TLS 指纹的库。
      • Python: tls_client, curl_cffi
      • Go: cycletls
    2. JS 层面
      • 如果通过 TLS 伪装后仍遇到 5秒盾,需要解析页面中的 JS 挑战(通常是 AES 运算或数学计算),算出 cf_clearance Cookie。
      • 捷径:使用“穿云API”类服务,或使用 DrissionPage (控制浏览器) 绕过。
  • 代码示例 (使用 tls_client 绕过检测)
python
import tls_client

session = tls_client.Session(
    client_identifier="chrome_120",  # 模拟 Chrome 120 的 TLS 指纹
    random_tls_extension_order=True
)

res = session.get(
    "https://example.com",
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..."
    }
)
print(res.status_code) # 通常能直接绕过 403

6. 工具与框架选择

方案优点缺点适用场景
:---:---:---:---
JSDOM成熟,API 全并不是真正的浏览器,特征指纹非常多 (如 canvas 实现差异)简单反爬,验证逻辑
vm2 + 手动补环境纯净,无多余特征,可控性最高开发成本极高,缺什么补什么,容易漏瑞数 4/5/6,Akamai,高难度对抗
浏览器自动化 (Puppeteer/Playwright)真实环境,无需补环境效率低,并发差,容易被检测指纹 (webdriver, CDP)少量数据抓取,无法破解 JS 时
unidbg (Android)模拟安卓环境很多网页反爬算法与 App 也就是一套逻辑,有时有奇效主要是 App 逆向,Web 辅助
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.7.1