前言
大家好,我是一名后端开发兼爬虫爱好者。今天想和大家聊聊爬虫逆向这个话题。
说到爬虫,很多人第一反应是 requests.get() 一把梭,HTML 解析完数据就到手了。但现实中的爬虫,尤其是在面对电商、社交媒体、内容平台时,往往会遇到这样的情况:
{
"code": 403,
"message": "invalid request",
"data": null
}
或者更令人头痛的——服务器返回了数据,但关键字段却是乱码,请求体里塞满了看不懂的加密参数。这时候,普通的爬虫手段已经不够用了,我们需要进入爬虫逆向的世界。
本文将从头梳理爬虫逆向的入门知识,涵盖 JS 混淆、调试技巧、实战案例以及法律边界,希望能帮你迈出第一步。
一、什么是爬虫逆向?为什么需要逆向?
爬虫逆向(Crawler Reverse Engineering),简单来说,就是通过分析前端代码(主要是 JavaScript)的执行过程,还原数据请求的完整逻辑,从而让爬虫能够模拟真实的请求行为。
为什么需要逆向?
现代 Web 应用大量采用前端加密和**反爬机制**来保护数据:
| 防护手段 | 说明 |
|---------|------|
| 参数签名(sign) | 对请求参数进行哈希/加密,服务端验签 |
| Token 鉴权 | 需先获取动态 token 才能请求数据 |
| 请求体加密 | 传输的数据使用 AES/RSA 加密 |
| 环境检测 | 检测浏览器指纹、WebDriver 特征 |
| 频率限制 | IP / 账号粒度的请求限频 |
要突破这些防护,我们就得搞清楚前端代码到底做了什么。
二、常见加密参数分析
1. sign 签名参数
最常见的反爬手段。客户端把请求参数按一定规则排序后拼接,再通过某个哈希算法(MD5、SHA1、SHA256)计算出一个固定长度的字符串。
典型的请求示例:
GET /api/list?page=1&pageSize=20&sign=3f7c...9a2e
如果直接修改 page 参数而不更新 `sign`,服务端就会返回 403。
2. token / authorization
许多接口需要在 Headers 中携带 token,这个 token 往往是通过某个加密算法动态生成的,有时还有过期时间。
3. 加密请求体
POST 请求的 body 可能是这样的:
{
"data": "U2FsdGVkX1+6...p8HVaQ==",
"sign": "a1b2c3..."
}
需要找到加密函数,理解加密流程,才能构造出合法的请求体。
三、JavaScript 调试工具
Chrome DevTools — 开发者的瑞士军刀
按 F12 或 `Ctrl+Shift+I` 打开 DevTools,下面几个面板是做逆向最常用的:
Sources 面板
这是逆向的核心战场。它可以:
- 查看页面加载的所有 JS 文件
- 设置断点(Breakpoints)
- 单步执行代码(Step Over / Step Into)
- 查看作用域变量(Scope)
- 监视表达式(Watch)
入门操作:
1. 打开目标网页
2. 切换到 Sources 面板
3. 按 Ctrl+P 搜索关键词(如 `sign`、`md5`、`encrypt`)
4. 在可疑代码行号上单击设置断点
5. 触发接口请求,观察断点是否命中
三种断点类型
| 类型 | 用途 |
|------|------|
| 普通断点(Line Breakpoint) | 停在指定代码行 |
| XHR/Fetch Breakpoint | 拦截特定 URL 的 AJAX 请求 |
| DOM Breakpoint | DOM 元素变化时暂停 |
Console 中的小技巧
在断点暂停时,可以随时在 Console 中执行代码来观察变量值或调用函数:
// 在 Console 中手动调用可疑函数
> md5("test")
"098f6bcd4621d373cade4e832627b4f6"
> btoa("hello")
"aGVsbG8="
这可以帮助我们快速验证对加密逻辑的猜测。
四、常见 JS 混淆技术识别
为了增加逆向难度,开发者通常会对 JS 代码进行混淆(Obfuscation)。下面是最常见的几种:
1. 变量名混淆
原始代码:
function encryptPassword(password, salt) {
const hashed = md5(password + salt);
return hashed;
}
混淆后:
function a(b, c) {
const d = e(b + c);
return d;
}
变量名被替换为短无意义的名称,降低可读性。
2. 字符串数组(String Array)
代码中的字符串被提取到一个数组中,通过下标引用:
var _0x1234 = ["md5", "password", "salt"];
function encrypt(_0x2a1b, _0x3c4d) {
return window[_0x1234[0]](_0x2a1b + _0x3c4d);
}
应对方法: 在 Console 中打印数组内容,或者直接在浏览器中展开 array 查看。
3. 控制流平坦化(Control Flow Flattening)
将顺序执行的代码打散,用 switch-case + while 循环重新组织:
var state = 0;
while (true) {
switch (state) {
case 0:
// 原始代码第 1 步
state = 3;
break;
case 3:
// 原始代码第 2 步
state = 1;
break;
case 1:
// 原始代码第 3 步
state = -1;
break;
default:
break loop;
}
}
应对方法: 不要试图在文本中静态还原,而是在浏览器中**动态调试**,关注实际执行的路径。
4. 代码自执行与加密
eval(function(p,a,c,k,e,d){...}('...'))
代码以加密字符串形式存在,运行时才解密执行。
应对方法: 在 eval 处设置断点,单步进入或直接在 Console 中打印解密后的代码。
五、逆向分析流程(核心方法论)
做逆向不是"瞎猜",而是有一套标准流程:
抓包 → 定位加密函数 → 分析逻辑 → 还原算法
第一步:抓包(Capture)
先用浏览器 DevTools 的 Network 面板捕获目标接口的请求,记录所有 Headers、Query Parameters、Request Body、Response。
重点观察:
- 哪些参数是动态变化的?
- 是否存在 sign / token / nonce 等可疑参数?
- 是否有额外的 Cookie 设置请求?
第二步:定位加密函数(Locate)
这是最核心也是最耗时的一步。
搜索关键词法: 在 Sources 面板中用 Ctrl+P 搜索 `sign`、`md5`、`sha1`、`encrypt`、`btoa`、`toHex` 等关键字。
XHR 断点法: 在 Sources 面板右侧的 XHR Breakpoints 中添加目标 URL 关键词,断点会在请求发出前暂停,然后查看调用栈(Call Stack)回溯到加密逻辑所在的位置。
堆栈回溯法: 断点命中后,查看 Call Stack,从栈底的"发起请求"函数一层层往上回溯,找到计算参数的逻辑。
第三步:分析逻辑(Analyze)
在断点处逐个检查变量值,理解参数是如何生成的。善用 Console 和 Watch 面板。
第四步:还原算法(Reimplement)
用 Python / Node.js 将分析出的加密逻辑重新实现,验证结果是否与浏览器中的输出一致。
六、实战案例:逆向一个简单的 sign 参数
下面我们从一个模拟场景出发,完整演示 sign 参数的逆向过程。
场景描述
假设某网站的搜索接口为:
POST /api/search
请求体:
{
"keyword": "手机",
"page": 1,
"sign": "fcb5a8a9f3d2c1b4e5f6a7b8c9d0e1f2"
}
我们从 Sources 面板搜索 sign,找到如下关键 JS 代码:
function generateSign(params) {
var keys = Object.keys(params).sort();
var str = "";
for (var i = 0; i < keys.length; i++) {
str += keys[i] + "=" + params[keys[i]] + "&";
}
str += "secret_key=abc123";
return md5(str);
}
分析过程
1. 抓包: 确认请求体包含 keyword、`page`、`sign` 三个字段
2. 定位: 搜索 sign,在 Sources 中找到 `generateSign` 函数
3. 分析: 在函数开头设置断点,触发请求,观察变量:
- `keys` = `["keyword", "page"]`(已排序)
- `str` = `"keyword=手机&page=1&secret_key=abc123"`
- 最终调用 `md5()` 生成 sign
4. 还原: 用 Python 实现
import hashlib
def generate_sign(params):
keys = sorted(params.keys())
raw = "&".join(f"{k}={params[k]}" for k in keys)
raw += "&secret_key=abc123"
return hashlib.md5(raw.encode()).hexdigest()
# 验证
params = {"keyword": "手机", "page": 1}
sign = generate_sign(params)
print(sign) # 应与浏览器中的 sign 一致
验证步骤
在 Chrome 的 Console 中手动调用 generateSign({"keyword": "手机", "page": 1}),对比输出与 Python 输出是否一致。一致说明还原成功。
七、常用辅助工具
除了 Chrome DevTools,以下工具也能大幅提升逆向效率:
Fiddler / Charles
- **功能:** HTTP/HTTPS 抓包代理
- **适用场景:** 手机 App 抓包、查看 HTTPS 请求详情
- **核心技巧:** 设置断点修改请求/响应,绕过客户端校验
mitmproxy
- **功能:** Python 驱动的中间人代理
- **适用场景:** 需要脚本化处理请求时,支持用 Python 写拦截规则
- **安装:** `pip install mitmproxy`
Chrome Overrides(本地替换)
- **功能:** 将远程 JS 文件替换为本地文件
- **适用场景:** 修改 JS 代码去掉加密逻辑,观察原始数据
- **使用方法:**
1. Sources > Overrides > Select folder for overrides
2. 在 Sources 中右键 JS 文件 > Save for overrides
3. 修改文件后保存,页面刷新后使用修改后的代码
ReRes(浏览器插件)
- **功能:** 类似 Overrides,但支持正则匹配 URL 并映射到本地文件
- **适用场景:** 快速替换 CDN 上的混淆 JS 为本地调试版本
八、逆向工程的法律边界与道德准则
最后,想认真和大家聊聊法律和道德问题。这一点比任何技术都重要。
⚠️ 高风险行为(请勿尝试)
- 绕过付费墙(Paywall)获取付费内容
- 获取用户隐私数据(手机号、身份证、通讯录等)
- 对政府、金融、医疗等关键信息系统进行逆向
- 将逆向获得的数据用于商业竞争或非法交易
- 破解或去除软件/服务的版权保护机制
✅ 可接受的合法用途
- 学习研究:仅用于个人学习和知识提升
- 公开 API 的合规使用:调用官方提供的公开接口
- 数据抓取需遵守平台的 `robots.txt` 及服务条款
- 安全研究:在授权范围内进行安全测试
技术人的自律
技术本身是中性的,但使用技术的人需要有底线。我个人的原则是:
**能爬不代表该爬,会逆向不代表可以滥用。**
建议大家在学习和研究时,选择目标明确公开、数据非敏感、且有合法授权或明确开放策略的网站。也可以用自己搭建的测试站点来练手。
九、总结与学习路径
本文带大家梳理了爬虫逆向入门的几个核心知识点:
| 知识点 | 掌握程度 |
|--------|---------|
| 逆向的基本概念与适用场景 | 理解 |
| 常见加密参数的识别 | 掌握 |
| Chrome DevTools 调试技巧 | 熟练 |
| 常见混淆技术的识别与应对 | 了解 |
| 逆向分析的标准流程 | 掌握 |
| 工具链的使用 | 熟悉 |
| 法律与道德边界 | 牢记 |
推荐的学习路径
1. 打好基础: 扎实的 JavaScript 基础(原型链、异步、模块化)
2. 熟悉工具: Chrome DevTools 用到肌肉记忆
3. 多动手: 找一些有公开 API 的网站练习分析
4. 阅读源码: 了解常见前端框架和加密库的实现
5. 持续学习: 反爬技术在进化,逆向技术也在进化
推荐资源
- **AST(抽象语法树)**:理解代码结构,用于还原混淆代码
- **JavaScript 反混淆工具:** [de4js](https://lelinhtinh.github.io/de4js/)、[jsnice.org](http://jsnice.org/)
- **Python 爬虫框架:** Scrapy、httpx、curl_cffi
- **逆向社区:** 看雪论坛、52PoJie、GitHub 爬虫项目
如果你看完这篇文章有所收获,欢迎分享给身边的朋友。下一篇我们会深入讲解 AST 还原混淆代码和**浏览器环境模拟**,敬请期待!
*本文仅供学习交流使用,请勿用于非法用途。*
评论