首页 / 文章

每个MCP服务器都是您的代理可能泄露的又一个密钥。

每个MCP服务器都意味着又一个正在运行的秘密,进而扩大了恶意输入所能影响的范围。应对令牌的作用域进行审计,并应用四项修复措施以缩小其破坏范围。

发布者:REACTAPP.TOP阅读约 4 分钟950 词

来源: Every MCP Server You Add Gives Your Agent Another Credential

一切起初都很简单。周一连接了 GitHub,周二连接了 Slack,接着是 Postgres,然后是 Notion,还有同事在某个下午编写但从未记录过的内部计费服务器。每一次新增都让这个自动化工具的功能更加强大,同时也为它携带的“密钥串”增添了一把钥匙。

问题往往是在偶然情况下暴露的——当有人正在调试其他无关问题时打开了配置文件。六台服务器,六组敏感信息,全都以明文形式存在于个人目录中,既没有过期时间也没有所有者。到了那时,MCP就不再显得是个方便的工具,反而变成了一个隐患。

数据统计

在几个月的热情使用之后,典型的配置情况如下:

{
  "mcpServers": {
    "gh": { "cmd": "gh-mcp",  "env": { "GH_TOKEN": "ghp_live_9f2a" } },
    "db": { "cmd": "pg-mcp",  "env": { "PG_URL": "postgres://app:hunter2@prod/main" } },
    "sl": { "cmd": "slk-mcp", "env": { "SLACK_TOKEN": "xoxb-live-771" } }
  }
}

三台服务器,三个密钥,一个文件,且不进行轮换。只需在常见的配置文件夹中搜索类似令牌的字符串,几秒钟内就能检查自己的机器。

grep -rIl "ghp_\|xoxb-\|sk-" ~/.config ~/.claude ~/Library 2>/dev/null | wc -l

运行它的人往往能得到超出预期的结果。原本以为只有三个,实际却有十一个,这种情况并不少见。

真正棘手的部分

存储在磁盘上的凭证只是问题中较为温和的一面;更严重的是,每一个凭证都由唯一的决策者掌控,而该决策者还需从互联网上获取相关文本。

                    one agent loop
                          |
      +---------+---------+---------+---------+
      |         |         |         |         |
    github    slack   postgres   notion    billing
   (14 scp)  (9 scp)  (rw all)  (rw ws)   (rw all)
      |         |         |         |         |
      +---------+---------+---------+---------+
                          |
                 one poisoned input

问题评论、Notion 页面或表格中的某一行都可能提出相应的行动建议,而处理该任务的智能体拥有执行这些行动所需的所有关键信息。这其实就是“伪装起来的混乱问题”。该智能体并未受到损害,它只是在提供帮助,却无法区分用户的指令与那些仅表面相似的文本。

衡量差距

一个有效的做法是记录两周内所有的工具调用情况,然后对比每个标记被允许执行的操作与它实际执行的操作。某次此类审计的结果如下:

| Service  |  Granted Scopes |         Scopes Used | Utilization |
| -------- | --------------: | ------------------: | ----------: |
| GitHub   |              14 |                   3 |       21.4% |
| Slack    |               9 |                   2 |       22.2% |
| Postgres |         Full RW | 1 table, reads only |     Minimal |
| Notion   | Whole workspace |             2 pages |     Minimal |

大约五分之四的授权访问权限从未被使用。这种状况并非出于便利考虑,而是意味着你承担了风险却得不到任何回报。

按收益排序的解决方案

每台服务器应拥有一个专用令牌,且该令牌仅用于该服务器的实际功能。共享令牌意味着责任共担;一旦出现问题,审计日志应指向服务器而非个人。

所有存储数据的对象默认都应设置为只读模式。只需两行SQL代码、一个专用角色,以及为代理程序实际需要读取的表设置相应的读取权限,就能将最糟糕的情况从表数据丢失转变为查询信息泄露。

create role agent login password 'rotate_me';
grant usage on schema public to agent;
grant select on orders, users to agent;

用短期令牌替代永久令牌。让保险库按需发放有效期仅为几分钟的凭证。周二上午被盗的密钥,到周二下午就已毫无价值。

async function tok(srv) {
  const r = await fetch(`${VAULT}/issue/${srv}`, { method: "POST" });
  const { token, ttl } = await r.json();
  return { token, exp: Date.now() + ttl * 1000 };
}

不仅要记录聊天内容,还要记录通话内容。为每个工具函数添加一个简单的封装,用于记录服务器信息、参数以及时间戳,只需几行代码即可实现。在上述审计中,这就暴露出了服务器调用了本不应访问的端点。

function wrap(name, fn) {
  return async (args) => {
    log({ srv: name, args, at: Date.now() });
    return fn(args);
  };
}

应遵循的规则

在引入新服务器之前,先假设它会具有攻击性,并思考在没有帮助的情况下它能获取什么。如果诚实的答案令人不安,那就缩小其权限范围或直接不引入该服务器。切勿承诺日后再解决这个问题,因为“日后”往往不会到来,尤其是在周五。

以上内容并非反对MCP。它确实解决了曾让智能体显得像玩具一样的集成混乱问题。关键在于,每添加一台服务器就会增加一个凭证,而这些凭证应当得到与生产环境中的其他密钥相同的重视程度。

相关阅读

  • 用文件夹和 Markdown 文件构建本地 LLM 智能体工作流 — 构建一个分阶段的本地智能体处理流程,每个阶段对应一个文件夹,提示词为可编辑的 Markdown 格式,且在执行昂贵操作之前由人工审核输出结果。
  • 可让 Claude 搜索团队操作手册的个性化 MCP 服务器 — 将 Markdown 格式的操作手册和事后分析报告索引到 ChromaDB 中,通过 MCP 服务器提供语义搜索功能,让 Claude 能在几秒钟内找到相关处理流程。