refactor: 将文件从子目录提升到仓库根目录
所有文件从 hello_js_reverse_skill/ 子目录移至仓库根目录, 使项目结构更清晰,便于作为 Skill 直接引用。 Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
# 协议层分析与对抗
|
||||
|
||||
## 概述
|
||||
|
||||
有些网站不仅在 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:使用浏览器自动化(最可靠)
|
||||
|
||||
```javascript
|
||||
// 使用 chrome-devtools MCP 在真实浏览器中执行请求
|
||||
// [chrome-devtools] evaluate_script
|
||||
const response = await fetch('https://target.com/api/data', {
|
||||
method: 'GET',
|
||||
headers: { 'Cookie': cookieValue },
|
||||
credentials: 'include'
|
||||
});
|
||||
const data = await response.json();
|
||||
```
|
||||
|
||||
```
|
||||
MCP 操作:
|
||||
[chrome-devtools] evaluate_script(function="fetch(url).then(r=>r.json()).then(d=>JSON.stringify(d))")
|
||||
```
|
||||
|
||||
#### 方案 B:curl-impersonate
|
||||
|
||||
```bash
|
||||
# 使用 curl-impersonate 模拟 Chrome 的 TLS 指纹
|
||||
curl_chrome116 https://target.com/api/data \
|
||||
-H "Cookie: session=xxx" \
|
||||
-H "User-Agent: Mozilla/5.0 ..."
|
||||
```
|
||||
|
||||
Node.js 中通过子进程调用:
|
||||
```javascript
|
||||
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 请求
|
||||
|
||||
```javascript
|
||||
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 设置
|
||||
|
||||
```javascript
|
||||
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 模拟
|
||||
|
||||
```
|
||||
[chrome-devtools] emulate(userAgent="自定义UA")
|
||||
```
|
||||
|
||||
## 4. Referer 校验
|
||||
|
||||
### 常见场景
|
||||
|
||||
- API 接口检查 Referer 头
|
||||
- 必须来自特定页面的请求
|
||||
- 缺少 Referer 返回 403
|
||||
|
||||
### 解决方案
|
||||
|
||||
```javascript
|
||||
headers: {
|
||||
'Referer': 'https://target.com/page',
|
||||
'Origin': 'https://target.com',
|
||||
}
|
||||
```
|
||||
|
||||
## 5. CORS 与跨域
|
||||
|
||||
### 预检请求 (Preflight)
|
||||
|
||||
```javascript
|
||||
// 某些请求会先发 OPTIONS 预检
|
||||
// 确保模拟请求时也处理 CORS 相关头
|
||||
headers: {
|
||||
'Origin': 'https://target.com',
|
||||
'Access-Control-Request-Method': 'POST',
|
||||
'Access-Control-Request-Headers': 'content-type',
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 请求频率限制
|
||||
|
||||
### 常见策略
|
||||
|
||||
- IP 维度限流
|
||||
- Cookie/Session 维度限流
|
||||
- 请求间隔检测
|
||||
- 滑动窗口计数
|
||||
|
||||
### 对抗方式
|
||||
|
||||
```javascript
|
||||
// 请求间隔控制
|
||||
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 封禁对抗
|
||||
|
||||
### 代理轮换
|
||||
|
||||
```javascript
|
||||
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 指纹问题
|
||||
```
|
||||
Reference in New Issue
Block a user