JianFeeeee
cf0ba1382c
fix(安全)★★: 停用(status='disabled')不拦鉴权 —— 两条路径都能绕过
## 缺口怎么被发现的
给公网 MCP 接入做验证时注册了一个一次性探针身份
(`mcp-wan-probe`),收尾执行 `UPDATE agents SET status='disabled'`,
本以为凭证就此失效。实测:
POST /api/v1/mcp(带该凭证) → 200
tools/call send_mail → 已发送(真的发出去了)
## 根因
`SetAgentDisabled` 这个 API 存在、返回成功,但 **status 只在投递方向被检查**
(`EnsureAgentDeliverable`,repo.go:209)。两条鉴权路径都不查:
VerifyAgent(ctx, name, secret) 选了 status 却从不判断 ← 缺口
VerifyAgentKey(ctx, token) 拿到名字直接返回 ← 同一个缺口,更严重
第二条要紧:Bearer key_token 正是 `middleware/auth.go` 注释里标「推荐」的
路径,官方建议用它 —— 它因此成了绕过停用的最短路。
缺口形状是「接口存在、返回成功、但只做了一半」,比没有这个接口更危险:
运维会以为停用已经生效。实测语义完全反了 ——
**停用只挡住了「别人给它发信」,没挡住「它自己发信」**。
## 修法
停用 ⇒ **拿不到 Agent 身份** ⇒ `AgentAuth` 直接 401,后续 handler 根本不执行。
这比「拿到身份后在某个业务分支拒绝」强:后者会让列表类 API 仍泄露身份存在。
两个细节:
* 返回 `sql.ErrNoRows`(而非自定义错误)⇒ 与「凭证不存在」**不可区分**,
否则可用该接口枚举出哪些名字是真实 Agent。判据里有专测这一格。
* status 检查放在 `wsJSON` 解析**之前** ⇒ 停用身份不会被解析出工作区,
那会让调用方以为它还「活着」。
## 判据(4 格)
**其中「反向对照」这格最关键**:`status='online'/'active'/''` 必须照常通过。
没有它,一个「永远返回 ErrNoRows」的 `VerifyAgent` 也是全绿的 ——
而那会让**所有** agent 都登不上,是比原缺口更大的事故。
**变异验证**:
撤掉 VerifyAgent 的 status 检查 → 3 格红 ✓
撤掉 VerifyAgentKey 的 status 检查 → 1 格红 ✓
全量 14 包绿。
2026-10-03 12:18:39 +08:00
..
2026-09-08 19:16:35 +08:00
2026-09-15 12:20:28 +08:00
2026-09-08 19:16:35 +08:00
2026-09-26 07:44:33 +08:00
2026-09-12 11:19:52 +08:00
2026-10-01 19:41:06 +08:00
2026-10-01 19:41:06 +08:00
2026-09-30 17:08:49 +08:00
2026-09-30 17:08:49 +08:00
2026-09-19 16:27:09 +08:00
2026-09-19 16:27:09 +08:00
2026-09-08 19:16:35 +08:00
2026-09-14 08:32:22 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-10-02 15:37:34 +08:00
2026-09-12 08:01:59 +08:00
2026-09-19 16:27:09 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-10-03 12:18:39 +08:00
2026-10-03 12:18:39 +08:00
2026-09-26 07:44:33 +08:00
2026-09-14 17:17:37 +08:00
2026-09-21 04:25:17 +08:00
2026-10-02 00:15:02 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-11 23:22:53 +08:00
2026-09-26 07:44:33 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-26 07:44:33 +08:00
2026-09-08 19:16:35 +08:00
2026-09-26 14:20:23 +08:00
2026-10-02 16:06:00 +08:00
2026-09-15 11:21:00 +08:00
2026-09-15 11:21:00 +08:00
2026-09-14 17:17:37 +08:00
2026-09-14 17:17:37 +08:00
2026-09-25 16:29:19 +08:00
2026-10-02 10:02:35 +08:00
2026-10-02 10:02:35 +08:00
2026-09-26 07:44:33 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-10-03 12:18:39 +08:00
2026-09-15 12:54:25 +08:00
2026-09-26 07:44:33 +08:00
2026-09-28 11:12:59 +08:00
2026-10-02 13:27:43 +08:00
2026-10-02 13:27:43 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-11 23:22:53 +08:00
2026-09-08 19:16:35 +08:00
2026-09-08 19:16:35 +08:00
2026-09-26 07:44:33 +08:00