逆向 API 的二分定位方法
接口文档没写、官方不告诉你、规则还三天两改——怎么科学地搞清楚一个黑盒接口到底校验了什么?答案不是”猜”,是控制变量 + 二分删减。
一句话定位
面对未公开/不稳定的 HTTP 接口,把”完整能跑的请求”作为基准,每次只改一个字段,看状态码变化反推校验规则。 这是逆向 API(黑盒接口分析,blackbox API analysis)的最朴素也最可靠的方法。
什么时候该用 / 不该用
该用
- 第三方代理/中转服务(没文档或文档与实际不符)
- 接口规则灰度变更(gray release,分批上线,部分用户先用上新逻辑),需要确认当下到底什么能跑
- 自家服务的”未文档化”接口(前端调后端,但 PRD 没写细节)
- 仿冒/兼容某个客户端的行为(如想让自己的程序”看起来像”官方客户端)
不该用
- 接口有完整官方文档且文档可信(直接查文档更快)
- 接口校验规则会触发安全告警(生产环境的认证接口,乱试会被风控拉黑)
- 校验逻辑明显在服务端代码里(能
grep源码就别瞎试)
标准操作流程(SOP)
1. 准备基准请求 → 一份"完整能跑通"的请求,状态码 200
2. 列出所有候选字段 → 请求头 / URL 参数 / 请求体所有 key
3. 单字段删减循环 → 每次只删一个字段,发请求,记录状态码
4. 单字段改值循环 → 对必需字段,改值看格式校验的边界
5. 复测与稳定性确认 → 关键结论各跑 2~3 次防偶发
6. 输出最小必需集 → 整理成"必需 / 可省 / 必需但值任意"三类
关键操作要点
① 一次只动一个变量 —— 同时改两个,结论就废了。这是控制变量法在协议层面的应用。
② 每个关键结论复测 ≥ 2 次 —— 网络偶发、上游限流、缓存命中都会污染单次结果。一次 200 不等于”通过”,连续 2 次 200 才算。
③ 看的是状态码 + 错误体,不是感觉 —— 200 400 403 429 500 503 520 每个码在不同代理里含义可能不一样,要看 body 里的 error 字段才能区分”真校验失败”还是”后端崩了”。
④ 删字段 vs 改值要分两步 —— 先用”删字段”找出必需项,再用”改值”找出每个必需项的格式边界(如长度、正则、枚举)。混着做会乱。
三大常见陷阱
陷阱 1:把”恰好能跑”当成”协议本意”
某天你测出 field_X 可以删,于是写代码不带 field_X。下周服务端开了校验,你的代理全挂。
防御原则:代理实现应默认携带”完整最小必需集”,而非依赖某次测试得出的”可省略”结论。 测试结论只用来调试,不用来精简生产请求。
陷阱 2:状态码语义被中间层改写
经过反向代理(如 Cloudflare、Nginx、自研网关)的请求,状态码经常不是源服务给的:
- 原本
400可能被包装成503或520 - 上游崩溃可能返回
500但 body 里写的是Panic detected,这不是参数错而是代码 bug - 限流
429跟”账号被封”403在某些代理里都返回503
心法:永远把状态码当成”线索”而不是”结论”,结论要靠 body 的 error message 来确认。
陷阱 3:灰度让结论”看起来矛盾”
同一个字段,A 同学测出”可省略”,B 同学测出”必需”,你以为有人搞错了——其实是服务端在分批灰度(部分账号、部分时段走新逻辑)。
应对:
- 多账号交叉验证
- 时间隔开(早上一遍、晚上一遍)
- 矛盾结论先记下来,标注时间戳和账号 ID,不要立刻覆盖旧结论
可迁移的场景
二分定位的核心不是”逆向 API”,是控制变量地缩小未知空间。它能直接迁移到:
| 场景 | 怎么用 |
|---|---|
| 调试 LLM Prompt 不稳定 | 从能跑的 Prompt 出发,每次只改一句,定位哪句在起作用 |
| 复现”偶发 bug” | 从能复现的最小输入出发,二分删行/删字段,缩到最小可复现 case |
| 排查依赖冲突 | 从能跑的 requirements.txt 出发,二分注释依赖找冲突项 |
| 排查 CSS 样式问题 | 从能渲染的 DOM 出发,二分删除样式类找出哪条规则在生效 |
| 排查慢查询 | 从慢 SQL 出发,二分删 JOIN / WHERE 条件找瓶颈 |
只要面对的是”黑盒 + 多变量 + 结果可观测”的局面,这个方法都成立。
配套工具与心智
工具
curl—— 最朴素的发请求工具,每次改一个字段最直观- HTTPie / Insomnia / Bruno —— 比 Postman 轻,适合写”参数化”的测试集
mitmproxy—— 抓真客户端的完整请求作为基准(最重要的一步是找到”完整能跑通”的样本)- 简单 shell 脚本 —— 字段多了就别手点,写个 for 循环跑全集
心智
- 先抓基准,再做减法 —— 没有”完整能跑”的基准,所有删减实验都是无源之水
- 承认接口会变 —— 写下结论时永远带日期。重读旧结论时先怀疑,再验证
- 结论要可证伪 —— “这个字段必需”是个可证伪命题(删掉跑一次就行);“这个字段可能必需”不是
完整案例骨架(脱敏)
来源:2026-04 某中转 API 的逆向分析(详见
04_探索日志/对应日期)
目标:搞清楚某中转 API 校验了请求的哪些字段。
步骤:
- 抓基准 —— 用官方客户端发一次成功请求,用抓包工具截下完整 HTTP(含所有头与 body)
- 删请求头 —— 完整请求 15 个头,每次只删一个,跑 2 次。结论:14 个可省,1 个必需(
anthropic-beta) - 删 URL 参数 —— 测出
?beta=true这种 query string 可省略 - 删请求体顶层字段 —— 测出
system/metadata/messages/model/max_tokens必需 - 拆 system 内部 ——
system是个数组,进一步测出第一个元素的text必须一字不差等于某固定字符串 - 拆 metadata 内部 —— 测出
user_id必需且必须匹配特定正则 - 改值找格式边界 —— 把
user_id改成各种值,确认是只校验格式还是校验具体值 - 汇总最小集 —— 输出一份”最小可通过请求”模板,标注每个字段为什么必需
用时:约 4 小时,发了约 200 个请求。
结论寿命:约 2 周后部分校验规则变更,需要重测。所以结论本身没多大长期价值,方法才有。
一句话收尾
黑盒接口面前,别猜,去测;别试一次,多测几次;别只看状态码,看 body。这套方法救过很多人也将救很多人。