Files
白夜 b5cf8b121a feat(v2.4.0): JSVMP 双路径攻克体系 + jsdom 环境补丁知识库
基于实战经验重构 JSVMP 分析框架:

- SKILL.md: 新增路径选择决策树(路径 A 算法追踪 vs 路径 B 环境伪装)
- SKILL.md: 路径 B「环境伪装六步法」完整方法论(采集→对比→分级→补丁→验证→端到端)
- SKILL.md: 新增场景 10「JSVMP + jsdom 环境伪装」、解法模式 E
- SKILL.md: 标注三板斧适用边界与局限,经验法则扩充至 22 条
- references/jsdom-env-patches.md: 新增 jsdom 环境补丁知识库(Function.toString 三层防御 / plugins 完整模拟 / DOM 布局属性 / 30+ API 存根)
- cases/: 新增经验库系统(模板 + 首个 JSVMP 实战案例含 58 项环境检测差异全表)
- references/jsvmp-analysis.md: JSVMP 专项分析详细指南
- references/troubleshooting.md: 常见问题排查指南
- templates/python-request/: Python 项目模板
- 各 references 文档增强、Python 技术栈支持、MCP v1.1 适配(44→52 工具)

Made-with: Cursor
2026-04-02 18:10:05 +08:00

6.7 KiB
Raw Permalink Blame History

协议层分析与对抗

概述

有些网站不仅在 JS 层面做加密保护,还在协议层面进行检测(TLS 指纹、HTTP/2 强制等)。 当算法全部还原正确但请求仍然失败时,需要考虑协议层问题。

1. TLS 指纹检测

原理

服务器通过分析 TLS Client Hello 报文中的特征来识别客户端类型:

  • Cipher Suites 列表和顺序
  • TLS 扩展列表和顺序
  • 支持的曲线(Elliptic Curves)
  • 签名算法
  • ALPN 协议列表

不同客户端(Chrome、Firefox、curl、Node.js)的 TLS 指纹不同。

检测表现

  • 请求返回 403 Forbidden
  • 返回空响应或错误页面
  • 返回 token failed、access denied 等自定义错误
  • 同样的参数在浏览器中正常,在 Node.js 中失败

解决方案

方案 A:使用 Camoufox 反检测浏览器(最可靠)

// 使用 camoufox-reverse MCP 在 Camoufox 浏览器环境中执行请求
// [camoufox-reverse] evaluate_js
const response = await fetch('https://target.com/api/data', {
    method: 'GET',
    headers: { 'Cookie': cookieValue },
    credentials: 'include'
});
const data = await response.json();
MCP 操作:
[camoufox-reverse] launch_browser()
[camoufox-reverse] navigate(url="https://target.com")
[camoufox-reverse] evaluate_js(expression="fetch(url, options).then(r=>r.json()).then(d=>JSON.stringify(d))")

方案 B:curl-impersonate

# 使用 curl-impersonate 模拟 Chrome 的 TLS 指纹
curl_chrome116 https://target.com/api/data \
    -H "Cookie: session=xxx" \
    -H "User-Agent: Mozilla/5.0 ..."

Node.js 中通过子进程调用:

const { execSync } = require('child_process');

function fetchWithChromeTLS(url, headers = {}) {
    const headerArgs = Object.entries(headers)
        .map(([k, v]) => `-H "${k}: ${v}"`)
        .join(' ');
    const result = execSync(`curl_chrome116 "${url}" ${headerArgs} -s`, {
        encoding: 'utf-8',
        timeout: 30000,
    });
    return JSON.parse(result);
}

方案 C:自定义 TLS(高级)

使用支持自定义 TLS 指纹的库(如 tls-client 的 Node.js 绑定)。

2. HTTP/2 协议

检测表现

  • HTTP/1.1 请求返回错误
  • HTTP/2 请求正常返回数据
  • 抓包可以看到服务器仅接受 h2 连接

Node.js HTTP/2 请求

const http2 = require('http2');

function http2Request(url, options = {}) {
    return new Promise((resolve, reject) => {
        const urlObj = new URL(url);
        const client = http2.connect(`${urlObj.protocol}//${urlObj.host}`);
        
        client.on('error', reject);
        
        const headers = {
            ':method': options.method || 'GET',
            ':path': urlObj.pathname + urlObj.search,
            ':scheme': urlObj.protocol.replace(':', ''),
            ':authority': urlObj.host,
            'user-agent': options.userAgent || 'Mozilla/5.0 ...',
            'accept': 'application/json',
            ...options.headers,
        };
        
        if (options.cookie) {
            headers['cookie'] = options.cookie;
        }
        
        const req = client.request(headers);
        
        let data = '';
        req.on('data', (chunk) => { data += chunk; });
        req.on('end', () => {
            client.close();
            resolve(data);
        });
        req.on('error', reject);
        
        if (options.body) {
            req.write(options.body);
        }
        req.end();
    });
}

// 使用示例
async function main() {
    const data = await http2Request('https://target.com/api/data?page=1', {
        headers: {
            'cookie': 'm=xxx; sessionid=yyy',
            'referer': 'https://target.com/',
        }
    });
    console.log(JSON.parse(data));
}

3. User-Agent 校验

常见场景

  • 某些页面要求特定 UA
  • 不同 UA 返回不同内容
  • 空 UA 或非浏览器 UA 被拒绝

Node.js 设置

const axios = require('axios');

const client = axios.create({
    headers: {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    }
});

MCP 侧验证

[camoufox-reverse] launch_browser(os_type="macos")
[camoufox-reverse] get_fingerprint_info
→ 验证当前浏览器环境中的 UA、平台和指纹是否与目标站点要求一致

4. Referer 校验

常见场景

  • API 接口检查 Referer 头
  • 必须来自特定页面的请求
  • 缺少 Referer 返回 403

解决方案

headers: {
    'Referer': 'https://target.com/page',
    'Origin': 'https://target.com',
}

5. CORS 与跨域

预检请求 (Preflight)

// 某些请求会先发 OPTIONS 预检
// 确保模拟请求时也处理 CORS 相关头
headers: {
    'Origin': 'https://target.com',
    'Access-Control-Request-Method': 'POST',
    'Access-Control-Request-Headers': 'content-type',
}

6. 请求频率限制

常见策略

  • IP 维度限流
  • Cookie/Session 维度限流
  • 请求间隔检测
  • 滑动窗口计数

对抗方式

// 请求间隔控制
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function fetchWithRateLimit(urls, delayMs = 1000) {
    const results = [];
    for (const url of urls) {
        const data = await fetch(url);
        results.push(data);
        await sleep(delayMs + Math.random() * 500); // 随机化延迟
    }
    return results;
}

7. IP 封禁对抗

代理轮换

const HttpsProxyAgent = require('https-proxy-agent');

const proxies = [
    'http://proxy1:port',
    'http://proxy2:port',
];

function getRandomProxy() {
    return proxies[Math.floor(Math.random() * proxies.length)];
}

async function fetchWithProxy(url, options = {}) {
    const agent = new HttpsProxyAgent(getRandomProxy());
    return fetch(url, { ...options, agent });
}

诊断流程

请求失败?
    │
    ├─ 检查 HTTP 状态码
    │   ├─ 403 → TLS 指纹 / Referer / UA / IP 封禁
    │   ├─ 412 → 前置条件失败(Cookie / Token 过期)
    │   ├─ 429 → 频率限制
    │   └─ 200 但数据异常 → 参数错误 / 加密不对
    │
    ├─ 同样的请求在浏览器中成功?
    │   ├─ 是 → TLS 指纹问题,切换到浏览器方案
    │   └─ 否 → 参数/Cookie 确实有问题,重新分析
    │
    ├─ curl 命令测试
    │   ├─ curl 成功 → Node.js 请求头/参数构造问题
    │   └─ curl 也失败 → TLS / 协议 / IP 问题
    │
    └─ 使用 HTTP/2?
        ├─ HTTP/2 成功 → 切换到 http2 模块
        └─ HTTP/2 也失败 → TLS 指纹问题