前言

大家好,我是一名后端开发兼爬虫爱好者。今天想和大家聊聊爬虫逆向这个话题。

说到爬虫,很多人第一反应是 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 还原混淆代码和**浏览器环境模拟**,敬请期待!


*本文仅供学习交流使用,请勿用于非法用途。*