摸鱼小记|API 抓包的初步尝试

API 抓包 / 接口分析的初步尝试

主要在 ai 的辅助下进行。

网站是如何工作的 ?

想象一个餐厅的场景:

  • 顾客 = 浏览器
  • 服务员 = 前端页面(我看到的界面)
  • 厨房 = 后端服务器(真正存数据的地方)
  • 菜单上的菜 = 数据

假设现在我们点击按钮/翻页(点菜)→ 浏览器会向服务器发 API 请求(服务员通知厨房)→ 服务器返回数据(厨房做好菜端出来)→ 前端渲染页面(服务员摆盘给你看)

因此可以发现在网页上看到的文字或图像,并不是"刻在网页上的",而是页面实时去服务器要的。这个"要"的过程,就叫做 API 请求

API 请求的格式

1
2
3
收件人:/api/study/lexicon/v1/list     ← 接口地址
发送方式:POST                          ← POST = 附带内容发送
信的内容:{ c_id: 438343, pagesize: 9999 }  ← 要什么

用户在浏览器里能看到服务器返回的数据——这就是 F12 开发者工具的作用。打开 Network(网络)标签,就能看到页面在偷偷发了哪些请求、收到了什么数据。

为什么不能直接发请求?——签名机制

你可能会想:既然知道地址和参数,我直接发请求不就行了?于是一个问题来了:厨房怎么知道信息是真人发送的,而步是有人冒充的?

一种解决方案是:在每封信上盖一个防伪印章,叫做 sign(签名)。

这个印章的制作方式:

1
把信的所有内容 → 按字母顺序排好 → 用一个"秘密配方"加密 → 生成一串数字

“秘密配方"就是 idictation_2024 这个密钥。

简单脚本做了什么 ?

① 补字段

1
2
3
4
5
6
7
8
原始请求:{ c_id: 438343 }
补完后变成:
{
  c_id: 438343,
  api_key: "%2Fapi%2Fstudy...",   ← 接口地址编码后
  timestamp: 1748000000,           ← 当前时间戳
  nonce: "a3f9k2m8xz",            ← 随机字符串(防重放攻击)
}

② 生成 sign

1
2
3
把上面所有字段 → 按 key 字母顺序排列 → 拼成一行字符串
→ 用 HMAC-SHA256 算法 + 密钥"idictation_2024"加密
→ 得到一串 hex 字符串 → 这就是 sign

③ 发出去拿数据

1
2
3
把补好字段+sign 的完整请求体 → POST 发到服务器
→ 服务器验证 sign 合法 → 返回数据
→ 脚本取出 json.values 里的内容

换一本词书怎么办 ?

只需要找到一个参数:** g_id ** 方法:

  1. 登录后打开你想要的那本词书
  2. 按 F12 → 切到 Network 标签
  3. 在词书页面点击任意章节或刷新
  4. 在 Network 里找到发往 /api/study/lexicon/ 的请求
  5. 点进去看请求内容,找 g_id 的值 然后把脚本里的 115172 换成你找到的数字就行。

实战

步骤 做什么 工具
1 找到数据从哪个接口来 F12 → Network
2 看请求参数有哪些字段 Network →目标请求的载荷(Payload)
3 判断有没有签名字段(sign/token 等) 同上
4 如果有签名,找签名逻辑 F 12 → Sources → 搜索密钥关键词
5 复现签名 + 发请求 Console 写脚本

第一步:先制造一个请求 Network 标签只记录你操作时发生的请求,所以要先有动作才有东西看。

  1. 打开 https://www.idictation.cn 并登录
  2. 按 F12 打开开发者工具
  3. 点击顶部的 Network 标签
  4. 然后在网页上点击任意一个词书或章节

第二步:筛选请求 Network 面板顶部有一排过滤按钮,找到 Fetch/XHR 。只看"页面偷偷发出去拿数据的请求”,过滤掉图片、CSS 等干扰项。

第三步:找到目标请求 过滤后,左边会出现一个列表。找名字里包含 listchapter 的条目,打开它。

第四步:找 Payload 点击请求后,右边会出现几个子标签:

  • Headers(表头)
  • Payload(载荷)← 这个
  • Preview / Response(返回的数据)

第五步:判断有没有 sign/token 字段

1
2
3
4
5
6
{g_id: 115172, api_key: "%2Fapi%2Fstudy%2Flexicon%2Fv2%2Fchapter%2Flist", timestamp: 1774249435,…}
api_key: "%2Fapi%2Fstudy%2Flexicon%2Fv2%2Fchapter%2Flist"
g_id: 115172
nonce: "614fjqnlce"
sign: "21fbabe524875399c8a547a19b2a1517970c1d66f5078269cac14f1c57324be8"
timestamp: 1774249435

第六步:找签名逻辑 在 Network 里把过滤从 Fetch/XHR 改成 JS 。接下来会看到几个 .js 文件,找名字最大的那个(通常叫 index-xxxxxxxx.js)。点进去,切到 Response 标签,能看到一堆压缩的代码

点顶部 “源代码/来源”(Sources)标签,用 Ctrl + Shift + F(全局搜索), secretsign

结果会很多,但你要找的是赋值语句,也就是长这样的:

1
2
e.data.sign = ...
xxx.sign = ...

找到赋值的地方,往上看几行,就能看到 sign 是怎么算出来的,密钥自然就露出来了。

我是如何使用 AI 的

原文摘录

当开始一个新的功能开发/需求时,我会首先定位到这个需求是基于哪个仓库开发,并同时打开 Claude Code 与 Codex 进行初始化,形成各个 Agent 对项目代码仓库的基础的文档沉淀。

如果是需要协同多个仓库开发的场景,可以定义一个外部的例如 feat-xxx/ 文件夹,并将相关的 git repo 都置于这个文件夹目录下,并进行初始化,后续 agent 都会在这个项目目录下执行,要注意的是,需要将每一个 repo 都切换到对应 feat 分支进行开发,以免后续代码版本管理混乱。接着向 codex 描述清楚相应的需求,让 codex 总结成详细的 feature 描述,并根据实际需求让 codex 进行调整,如果需求相对清晰简单,可以直接让 codex 执行即可。

如果牵扯到代码复杂度较高,可以采用 Claude Code 的自定义命令 ,生成较为详细的 PRPs/ 文档,主要流程为:

  • 在 Claude Code 中执行 /generate-prp 命令,在命令之后输入 codex 生成的 feature 描述
  • Claude Code 命令会根据模板和提供的功能需求生成一份详尽的需求文档,会在 PRPs/feat-xxx.md 中,可以继续在对话中进行修改调整,需求完成后, 调用 /clear 命令来清理当前上下文
  • 通过 Claude Code 执行 /execute-prp PRPs/feat-xxx.md 命令来完成需求,时间相对比较长,如因网络等问题中断,可以重复执行命令(进度与 TODO 会在文档中标注)

PRP 大体框架如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# Product Requirements Document (PRD)

## Objective
- [Clearly defined, measurable feature goals]

## Technical Constraints
- [Non-negotiable technical decisions]
- [Architectural principles that must be followed]

## Quality Standards
- [Performance benchmarks]
- [Maintainability requirements]
- [Test coverage criteria]

## Integration Requirements
- [External dependencies inventory]
- [Interface specifications]

## Deliverables Definition
- [Code organization patterns]
- [Documentation requirements]
思考

没有实际开发经验就没有这种自上而下的经验模式