下面这套命令,你在发布前(线上老版本)和发布后(新版本)各跑一遍,对比 HTTP 状态码就知道哪里变了。
先设一个变量(替换成你的线上地址,注意别带 /sse 后缀,用 /mcp):
bash
export MCP_URL='https://mobile.aow.com/pmd-mcp/mcp' # 你的线上地址,按实际改命令 1:完全空 header(漏洞扫描器的核心攻击)
bash
curl -sS -X POST "$MCP_URL" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"scanner","version":"1.0"}}}' \
-w '\n=====HTTP=%{http_code}=====\n'| 发布前(老版本) | 发布后(新版本) | |
|---|---|---|
| 状态码 | HTTP=200(或 -32000,但都是进了协议层) | HTTP=401 |
| body | JSON-RPC 返回 serverInfo / tools | {"error":{"code":-32001,"message":"Unauthorized..."}} |
这一条是判定漏洞的关键:发布前返回 200 或 JSON-RPC 错误 = 漏洞成立;发布后返回 401 = 已修复。
命令 2:枚举工具列表(拿到 36 个 tools schema)
bash
curl -sS -X POST "$MCP_URL" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
-w '\n=====HTTP=%{http_code}=====\n'| 发布前 | 发布后 | |
|---|---|---|
| 状态码 | HTTP=200,body 里是 36 个工具名 | HTTP=401 |
这一条是漏洞扫描器"证据链":发布前能枚举出 cr_approve / upload / session-log ... = 实锤;发布后 401 = 拿不到。
命令 3:带正确 Bearer(验证新鉴权门对正常调用方放行)
发布后你需要在服务端配了 MCP_AUTH_TOKEN,把 token 换成实际值:
bash
export MCP_TOKEN='你的密钥'
curl -sS -X POST "$MCP_URL" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "Authorization: Bearer $MCP_TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"scanner","version":"1.0"}}}' \
-w '\n=====HTTP=%{http_code}=====\n'| 发布前 | 发布后 | |
|---|---|---|
| 状态码 | HTTP=200(老版本根本没校验 Bearer) | HTTP=200(token 正确放行) |
命令 4:带错 Bearer(验证不会"带错还放行")
bash
curl -sS -X POST "$MCP_URL" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Authorization: Bearer 随便乱写一个错的token' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
-w '\n=====HTTP=%{http_code}=====\n'| 发布前 | 发布后 | |
|---|---|---|
| 状态码 | HTTP=200(老版本不校验,带啥都放行) | HTTP=401(错 token 拒绝) |
命令 5:带 rid+rtoken(验证老调用方兼容,不回归)
bash
curl -sS -X POST "$MCP_URL" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'rid: 你的rid' \
-H 'rtoken: 你的rtoken' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"scanner","version":"1.0"}}}' \
-w '\n=====HTTP=%{http_code}=====\n'| 发布前 | 发布后 | |
|---|---|---|
| 状态码 | HTTP=200 | HTTP=200(rid+rtoken 放行) |
这条是防回归:老调用方(Knot/CodeBuddy 走 rid+rtoken)发布后必须还是 200,否则你发布会把现有用户全踢下线。
对比结论一句话
发布前后唯一的区别,就是命令 1 和 2 的状态码从「200/进协议层」变成「401」。命令 3、4、5 保持 200(正常放行)+ 401(错 token 拒绝)不变。