MCP 最大的安全风险不是”连接被窃听”,而是工具投毒:一个看起来正常的 MCP 服务器,在工具描述或返回结果里藏指令,模型照做之后就会调用你的高权限工具、读取敏感文件并把数据发到攻击者端点。防护的核心不是”别用 MCP”,而是把信任校验放到运行时、把权限控制放到服务端,不要指望系统提示词能拦住注入。
五类典型风险
| 风险 | 怎么发生的 | 关键防护 |
|---|---|---|
| 工具投毒(Tool Poisoning) | 工具描述、参数 schema 或返回值里嵌入隐藏指令,模型当作可信上下文执行 | 输出结构化为固定 JSON schema,拒绝不匹配形状的返回;隔离高权限工具 |
| 地毯式抽换(Rug Pull) | 服务器在用户批准后修改工具定义,把可信工具变成恶意工具 | 对工具定义做哈希锁定,变更即告警 |
| 混淆代理人(Confused Deputy) | 服务器用自己过宽的权限替未授权用户执行动作 | OAuth 2.1 + 受众受限的短令牌;服务端按请求者身份校验 |
| 本地服务器失陷 | 本地 MCP 服务器以客户端同等级权限运行,可被诱导任意命令执行 | 沙箱运行、最小权限、启动前展示完整命令并需用户确认 |
| SSRF 与数据外带 | 模型参数里的 URL 被用来访问内网或云元数据端点 | 出网白名单,禁止访问内网与元数据地址 |
为什么工具投毒这么容易得手
根因是一个信任的时间差:工具描述只在连接时被审查一次,而工具返回结果每次都会直接进入模型上下文,且没有任何等价检查。攻击者正是利用这条未设防的运行时通道。 OWASP 把 MCP 工具投毒归类为一种间接提示词注入——服务器返回的文本里混着”合规指令”,模型分不清哪句是数据、哪句是指令。
MCP 官方规范自己也很克制:它明确写了”工具描述等注解应被视为不可信,除非来自受信任的服务器”,并且要求主机在调用任何工具前必须取得用户的明确同意。规范无法在协议层强制执行这些原则,落地责任在实现方。
七条可执行的防护清单
- 维护服务器白名单:不允许用户随意接入任意服务器,接入前做来源与作者核验。
- 锁定工具定义:对工具描述和参数 schema 做哈希,变更触发告警,直接挡住 rug pull 。
- 严格参数 schema:
additionalProperties: false,字符串字段加pattern,只接受声明过的参数与合法格式。 - 沙箱运行本地服务器:容器或应用层沙箱,限制文件系统可见范围,默认断网。
- 敏感操作强制人工确认:展示完整调用参数而不只是工具名,确认 UI 不能被模型生成的内容绕过。
- 出网白名单:禁止由模型参数决定任意 URL 抓取,阻断内网与云元数据地址。
- 会话与令牌:会话 ID 用加密随机并与用户身份绑定(如
<user_id>:<session_id>),远程传输强制 TLS,OAuth 用带 PKCE 的授权码流并做受众限制。
本地 vs 远程:风险点不同
本地 stdio 服务器的主要风险是任意代码执行与无感知——用户看不到将执行什么命令。所以客户端必须完整展示命令(含参数)、标注危险模式(sudo 、 rm -rf 、越权目录访问),并在沙箱里启动。
远程服务器的主要风险是认证与会话。用 MCP 传输方式对比里的结论:stdio 适合必须碰用户本机的场景,Streamable HTTP 适合包装网络 API 和多人共用,但后者必须补齐认证、会话绑定和出网控制这三条。搭建时可以参考MCP Server 搭建教程,把上面七条在写第一行代码时就设计进去,比事后加固便宜得多。
更上层的提示词注入防御思路(输入过滤、权限分层、输出审查)在提示词注入怎么防里有完整拆解,两篇配合看更完整。
接入一个第三方 MCP 服务器前的检查项
- 作者与命名空间是否可核验(域名/GitHub 归属)
- 源码是否公开、最近一次提交时间
- 工具描述里是否有”必须””强制””系统指令”等异常措辞
- 工具实际需要的权限是否明显超出其宣称功能
- 是否有出网行为、目标地址是否固定
- 本地包是否会被以客户端同等权限执行
- 是否支持在审批时展示完整调用参数









评论 (0)