CDP 抓包三板斧:Network.enable、requestWillBeSent、getResponseBody

举报
yd_241537561 发表于 2026/10/24 07:04:43 2026/10/24
【摘要】 不用代理、不用 F12:启用 Network 域后过滤 requestWillBeSent 就能拿到真实请求体,配 loadingFinished + getResponseBody 取响应,再拿 performance 的资源清单反查 SPA 的接口路径。

逆向站内接口时最常见的困境是:页面能打开,接口路径不知道;接口知道,字段不知道。过去我靠往页面里注入 fetch 钩子(把请求记到 window.__net),但有些页面会在文档早期就发完关键请求,钩子装晚了就是空的,还会误判成「按钮没绑事件」。Chrome DevTools Protocol 的 Network 域是外置的,不依赖注入,这三招够覆盖九成场景。

一、抓请求体:Network.enable + requestWillBeSent

ws = page_ws("")                      # 选中页面 target 的 websocket
cdp_call(ws, "Network.enable")
navigate(ws, url)
ws.settimeout(2)
while time.time() < end:
    m = json.loads(ws.recv())
    if m.get("method") != "Network.requestWillBeSent":
        continue
    req = m["params"]["request"]
    u = req.get("url", "")
    if u.endswith((".js", ".css", ".png", ".jpg", ".svg")) or "埋点域名" in u:
        continue
    print(req["method"], u, (req.get("postData") or "")[:400])

postData 对 JSON 请求直接可用;表单类还能看到 hasUserData/requestPostData 的截断标记,需要完整体时再取一次。

二、取响应体:一定在 loadingFinished 之后按 requestId 取

if m.get("method") == "Network.loadingFinished" and p.get("requestId") in wanted:
    b = cdp_call(ws, "Network.getResponseBody", {"requestId": p["requestId"]})
    print((b.get("body") or "")[:400])

坑在于时机:页面跳转或请求记录被淘汰后会报 -32000 No resource with given identifier found。我的做法是把 requestId 先存下来,收到 loadingFinished 立刻取,并且接受「取不到」不算失败——请求体往往已经足够定位问题。

三、反查接口路径:performance 的资源清单

SPA 的接口路径不在 HTML 里,页面又是前端路由,直接猜 URL 会撞出一堆 no route matches。最省事的是问浏览器 itself 加载过什么:

JSON.stringify(performance.getEntriesByType('resource')
  .map(e => e.name)
  .filter(u => /activity|event|signup/i.test(u))
  .slice(0, 60))

我就是这么发现活动列表接口的:fwdu/rest/developer/user/.../get-activity-list 无论怎么传参都返回 HD.35009999 internal error,而页面真正用的是另一条fwdo/rest/developer/servlet/.../activity/hwc/get-activity-list,一次返回 790 条。两条路径同前缀同服务名,差别只在 fwdu/user 与 fwdo/servlet——靠猜要猜到明天。

顺手一条:页内 fetch 复用登录态

expr = "(async () => { const csrf = (await (await fetch('/api/get-ainfo'))" 
"
        "    .headers.get('csrf')) || ''; ... })()"
cdp_call(ws, "Runtime.evaluate",
         {"expression": expr, "awaitPromise": True, "returnByValue": True})

要写 awaitPromise: True,否则 async IIFE 只回一个空对象。但这条也不是万能的:跨子域时 get-ainfo 的响应头不在 CORS 暴露清单里,页内取到的 csrf 会是 null。这时候要回到同源那侧发请求,或者直接把自己会话的 Cookie 收割下来用 requests 发。

三板斧的共同点是:观测外部化。不注入脚本、不改页面、不碰用户操作,抓到的就是线上真实发出的东西,省下的都是猜的时间。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。