Skip to main content

介绍

目的和范围

本文档为模型上下文协议(MCP)提供安全注意事项,并对 MCP 授权 规范形成补充。本文档识别了特定于 MCP 实现的安全风险、攻击向量 以及最佳实践。 本文档的主要受众包括实现 MCP 授权流程的开发者、MCP 服务器运营者以及评估基于 MCP 的系统的安全专业人员。阅读本文档时应同时参考 MCP 授权规范和 OAuth 2.0 安全最佳实践

攻击与缓解措施

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

困惑的代理问题

攻击者可以利用连接到第三方 API 的 MCP 代理服务器,造成 “困惑的代理” 漏洞。此攻击允许恶意客户端通过利用 静态客户端 ID、动态客户端注册以及 同意 cookie 的组合,在未获得用户适当同意的情况下获取 授权码。

术语

MCP 代理服务器 : 一个将 MCP 客户端连接到第三方 API 的 MCP 服务器,提供 MCP 功能,同时代理操作并作为单一 OAuth 客户端与第三方 API 服务器交互。 第三方授权服务器 : 保护第三方 API 的授权服务器。它可能不支持 动态客户端注册,因此要求 MCP 代理对所有请求使用 静态客户端 ID。 第三方 API : 提供实际 API 功能的受保护资源服务器。访问此 API 需要由 第三方授权服务器签发的令牌。 静态客户端 ID : MCP 代理服务器在与第三方授权服务器 通信时使用的固定 OAuth 2.0 客户端标识符。该 Client ID 指的是作为客户端访问第三方 API 的 MCP 服务器。无论哪个 MCP 客户端发起请求, 对于所有 MCP 服务器到第三方 API 的交互, 其值都相同。

易受攻击的条件

当同时存在以下所有条件时,这种攻击才成为可能:
  • MCP 代理服务器使用带有第三方 授权服务器的 静态客户端 ID
  • MCP 代理服务器允许 MCP 客户端 动态注册(每个都获得自己的 client_id)
  • 第三方授权服务器在首次授权后设置 同意 cookie
  • MCP 代理服务器在转发到第三方授权之前没有实现正确的按客户端同意

架构和攻击流程

正常的 OAuth 代理使用方式(保留用户同意)
恶意的 OAuth 代理使用方式(跳过用户同意)

攻击描述

当 MCP 代理服务器使用静态客户端 ID 与 第三方授权服务器进行认证时,以下攻击就成为 可能:
  1. 用户通过 MCP 代理服务器正常认证,以访问 第三方 API
  2. 在此流程中,第三方授权服务器会在用户代理上设置一个 cookie, 表示已对静态客户端 ID 同意
  3. 攻击者稍后向用户发送一个恶意链接,其中包含 精心构造的授权请求,该请求包含恶意重定向 URI, 同时带有一个新动态注册的客户端 ID
  4. 当用户点击该链接时,其浏览器仍然保留着之前合法请求中的 同意 cookie
  5. 第三方授权服务器检测到该 cookie,并跳过 同意界面
  6. MCP 授权码被重定向到攻击者的服务器 (在 动态客户端注册 中的恶意 redirect_uri 参数所指定)
  7. 攻击者将窃取的授权码兑换为 MCP 服务器的访问 令牌,且无需用户明确批准
  8. 攻击者现在可以作为被攻陷的 用户访问第三方 API

缓解措施

为防止困惑的代理攻击,MCP 代理服务器 必须 按如下所述实现 按客户端同意和适当的安全控制。
同意流程实现
下图展示了如何正确实现运行在 第三方授权流程之前的按客户端同意:
必需的保护措施
按客户端同意存储 MCP 代理服务器 必须
  • 为每个用户维护已批准 client_id 值的注册表
  • 在启动第三方 授权流程之前检查该注册表
  • 安全地存储同意决定(服务器端数据库,或服务器 特定 cookie)
同意 UI 要求 MCP 级别的同意页面 必须
  • 清楚标识请求的 MCP 客户端名称
  • 显示正在请求的具体第三方 API scopes
  • 显示将发送令牌的已注册 redirect_uri
  • 实现 CSRF 防护(例如 state 参数、CSRF token)
  • 通过 frame-ancestors CSP 指令或 X-Frame-Options: DENY 防止被 iframe 嵌套,以避免点击劫持
同意 Cookie 安全 如果使用 cookie 跟踪同意决定,则它们 必须
  • 对 cookie 名称使用 __Host- 前缀
  • 设置 SecureHttpOnlySameSite=Lax 属性
  • 经过密码学签名,或使用服务器端会话
  • 绑定到特定的 client_id(而不只是“用户已同意”)
Redirect URI 验证 MCP 代理服务器 必须
  • 验证授权请求中的 redirect_uri 与已注册 URI 完全 匹配
  • 如果 redirect_uri 在未重新注册的情况下发生变化,则拒绝请求
  • 使用精确字符串匹配(而不是模式匹配或通配符)
OAuth State 参数验证 OAuth state 参数对于防止授权码 拦截和 CSRF 攻击至关重要。正确的 state 验证可确保 在授权端点的同意批准会在回调端点得到强制执行。 实现 OAuth 流程的 MCP 代理服务器 必须
  • 为每个授权请求生成一个密码学安全的随机 state
  • 仅在同意被明确批准后,才将该 state 值存储到服务器端 (在安全会话存储或加密 cookie 中)
  • 在重定向到第三方身份提供方 之前立即设置 state 跟踪 cookie/会话(而不是在同意 批准之前)
  • 在回调端点验证 state 查询参数 与回调请求的 cookie 中或请求的基于 cookie 的会话中存储的值完全匹配
  • 拒绝任何 state 参数缺失 或不匹配的回调请求
  • 确保 state 值仅可使用一次(验证后删除),且 具有较短的过期时间(例如 10 分钟)
在用户于 MCP 服务器的授权端点批准同意界面之前, 包含 state 值的同意 cookie 或会话 不得 被设置。 在同意批准之前设置此 cookie 会使同意界面失效,因为攻击者可以通过构造恶意授权请求绕过它。

Token 透传

“Token 透传”是一种反模式,指 MCP 服务器在未验证这些 token 是否已正确签发给 MCP 服务器 的情况下,就接受来自 MCP 客户端的 token,并将其传递给下游 API。 如果服务器接受了为其他资源签发的 token,攻击者就可能获得未授权访问权限,或者以其他方式危害 MCP 服务器。此漏洞有两个关键维度:
  1. 受众验证失败。 当 MCP 服务器没有验证 token 是否专门面向自身(例如,通过受众声明,正如 RFC9068 中所述),它可能会接受最初为其他服务签发的 token。这会破坏 OAuth 的基本安全边界,使攻击者能够在不同于预期的服务之间复用合法 token。
  2. Token 透传。 如果 MCP 服务器不仅接受受众错误的 token,还将这些未修改的 token 转发给下游服务,就可能引发“困惑的代理”问题,下游 API 可能会错误地信任该 token,仿佛它来自 MCP 服务器,或者假定该 token 已由上游 API 验证过。

风险

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

缓解措施

MCP 服务器绝不能接受任何未明确签发给 MCP 服务器的 token。

服务端请求伪造(SSRF)

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

攻击描述

在 OAuth 元数据发现过程中,MCP 客户端会从多个可能被恶意 MCP 服务器控制的来源获取 URL:
  1. WWW-Authenticate 响应头中的 resource_metadata URL
  2. 受保护资源元数据文档中的 authorization_servers URLs
  3. 授权服务器元数据中的 token_endpointauthorization_endpoint 以及其他 URLs
恶意 MCP 服务器可以将这些字段填充为指向内部资源的 URL,从而启用以下攻击模式:
  • 直接访问内部 IP:如 http://192.168.1.1/adminhttp://10.0.0.1/api 之类的 URL 会指向内部网络服务
  • 云元数据端点:指向 http://169.254.169.254/(AWS/GCP/Azure 元数据服务)的 URL 可能泄露云凭证和实例信息
  • 本地主机服务:如 http://localhost:6379/ 之类的 URL 可以与本地服务(Redis、数据库、管理面板)交互
  • DNS 重新绑定:在验证与使用之间更改 DNS 解析结果的域名(例如,https://attacker.com 最初解析到安全 IP,随后解析到 192.168.1.1
  • 重定向链:看起来正常的 URL 可能重定向到内部资源

风险

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

缓解措施

部署到服务器上的 MCP 客户端 MUST 考虑 SSRF 风险,并在获取与 OAuth 相关的 URL 时实施适当的缓解措施。哪些防护措施合适取决于你的网络环境。 强制使用 HTTPS MCP 客户端在生产环境中 SHOULD 要求所有与 OAuth 相关的 URL 使用 HTTPS:
  • 拒绝 http:// URL,开发期间对环回地址(localhost127.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/8172.16.0.0/12192.168.0.0/16
  • 环回:127.0.0.0/8::1(除非为开发明确允许)
  • 链路本地:169.254.0.0/16(包括云元数据端点)
  • 私有 IPv6 段:fc00::/7fe80::/10
避免手动实现 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 服务器 必须 验证所有传入 请求。MCP 服务器 不得 将持有状态句柄视为身份验证。 MCP 服务器 应当 使用通过安全随机数生成器生成的安全、不可预测的句柄。避免使用可预测或顺序递增的 标识符,因为攻击者可能会猜到它们。设置句柄过期时间也可以 降低风险。 MCP 服务器 应当 在服务器端将句柄绑定到经过身份验证的 用户,例如将存储的状态键设为 <user_id>:<handle>,其中 用户 ID 来源于已验证的令牌而不是由客户端提供,并拒绝任何其他主体提交的句柄。这样可以 确保即使攻击者猜到了句柄,也无法 冒充其他用户。 有关在协议版本 2025-11-25 及更早版本中使用的服务器分配会话 ID 的安全建议,请参见 本页 2025-11-25 版本中的会话劫持

本地 MCP 服务器被攻破

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

攻击描述

本地 MCP 服务器是被下载并在与 MCP 客户端相同机器上执行的二进制程序。 如果没有适当的沙箱隔离和同意要求,以下攻击就成为可能:
  1. 攻击者在客户端配置中包含一个恶意的“启动”命令
  2. 攻击者在服务器本身内部分发恶意载荷
  3. 攻击者通过 DNS 重绑定访问一个留在 localhost 上运行的不安全本地服务器
可嵌入的恶意启动命令示例:

风险

限制不足或来自不受信任来源的本地 MCP 服务器会带来若干严重的安全风险:
  • 任意代码执行。攻击者可以使用 MCP 客户端权限执行任何命令。
  • 缺乏可见性。用户无法了解正在执行哪些命令。
  • 命令混淆。恶意行为者可以使用复杂或晦涩的命令来伪装成合法行为。
  • 数据外泄。攻击者可以通过被入侵的 JavaScript 访问合法的本地 MCP 服务器。
  • 数据丢失。攻击者或合法服务器中的漏洞都可能导致主机上的数据不可恢复地丢失。

缓解措施

如果 MCP 客户端支持一键式本地 MCP 服务器配置, 则在执行命令之前 MUST 实现适当的同意机制。 配置前同意 在通过一键配置连接新的本地 MCP 服务器之前,显示一个清晰的同意对话框。MCP 客户端 MUST
  • 显示将要执行的确切命令,不得截断(包括参数和参数值)
  • 明确标识这是一个会在用户系统上执行代码的潜在危险操作
  • 在继续之前要求用户明确批准
  • 允许用户取消配置
MCP 客户端 SHOULD 实现额外的检查和防护措施,以减轻潜在的代码执行攻击向量:
  • 高亮显示潜在危险的命令模式(例如,包含 sudorm -rf、网络操作、访问预期目录之外的文件系统的命令)
  • 对访问敏感位置(主目录、SSH 密钥、系统目录)的命令显示警告
  • 提醒 MCP 服务器以与客户端相同的权限运行
  • 在具有最小默认权限的沙箱环境中执行 MCP 服务器命令
  • 以受限方式启动 MCP 服务器,限制其对文件系统、网络和其他系统资源的访问
  • 提供机制,让用户在需要时显式授予额外权限(例如,特定目录访问、网络访问)
  • 使用适合平台的沙箱技术(容器、chroot、应用沙箱等)
  • 保持沙箱解决方案处于最新状态,以应对新出现的漏洞
旨在本地运行其服务器的 MCP 服务器 SHOULD 实施措施,以防止恶意进程的未授权使用:
  • 使用 stdio 传输以将访问限制为仅 MCP 客户端
  • 如果使用 HTTP 传输,则限制访问,例如:
    • 要求授权令牌
    • 使用 unix 域套接字或其他具有受限访问的进程间通信(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 传输安全

风险

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

缓解措施

URL 协议校验 MCP 客户端 必须 验证授权 URL 并拒绝危险协议:
  • 必须 仅允许授权 URL 使用 http://https:// 协议。 http:// 协议仅在本地开发期间对回环地址(如 localhost127.0.0.1::1)可接受;生产环境中的授权 服务器 必须 使用 https://
  • 必须 拒绝 javascript:data:file:vbscript: 以及其他潜在危险协议
  • 应当 使用基于允许列表的校验,而不是基于阻止列表的方法
安全打开 URL MCP 客户端 必须 避免在打开 URL 时执行 shell:
  • 禁止 使用 shell 命令(例如 cmd.exesh、PowerShell)来打开 URL
  • 应当 使用平台特定的、非 shell 的 URL 打开机制
内容安全策略(CSP) 基于 Web 的 MCP 客户端 应当 实施内容安全策略头,以防止 JavaScript 执行:
  • 设置 script-src 'self' 以防止执行内联 JavaScript
  • 使用 default-src 'self' 来限制资源加载
  • 对需要内联脚本的动态内容,可考虑使用 script-src 'nonce-<random>'
输入净化 MCP 客户端 必须 对从 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 代理服务应当针对 stdio 传输实施额外的安全控制:
  • 为所启动的进程实施沙箱或容器化
  • 限制所启动的 MCP 服务器对文件系统的访问
  • 记录所有 stdio 传输的使用情况,以便进行安全监控
  • 对可能具有危险性的命令要求额外授权
客户端保护措施 MCP 客户端应当实施纵深防御措施:
  • 在可能的情况下,将代理通信隔离在独立的安全上下文中
  • 对代理进程权限采用最小权限原则
  • 为代理服务本身实施进程级沙箱
  • 考虑在容器或受限环境中运行代理層

混淆攻击

攻击描述

一个 MCP 客户端在其生命周期内通常会与多个授权服务器交互。控制其中一个授权服务器的攻击者可能会试图让客户端向其发送由另一个诚实授权服务器签发的授权码或令牌(这是一种混淆攻击,见 RFC9207 第 1 节)。

缓解措施

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

本地主机重定向 URI 冒充

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

攻击描述

攻击者可以通过以下方式冒充任意客户端:
  1. 提供合法客户端的元数据 URL 作为其 client_id
  2. 绑定到任意 localhost 端口,并将该地址作为 redirect_uri 提供
  3. 当用户批准后,通过重定向接收授权码
服务器会看到合法客户端的元数据文档,而用户会看到合法客户端的名称,这使得攻击更难被发现。

缓解措施

请参见授权规范中的 本地主机重定向 URI 风险,其中说明了授权服务器应采取的对策,包括针对仅限 localhost 的重定向 URI 显示额外警告,并在授权过程中清楚显示重定向 URI 的主机名。

CIMD 信任策略

接受 客户端 ID 元数据文档 的授权服务器,可以应用基于域的信任策略来决定接受哪些基于 URL 的 客户端 ID:
  • 对受信任域的允许列表(适用于受保护的服务器)
  • 接受任何 HTTPS client_id(适用于开放服务器)
  • 对未知域进行信誉检查
  • 基于域名年龄或证书验证的限制
  • 显著展示 CIMD 及其他相关客户端主机名 以防止网络钓鱼
服务器对其访问策略保留完全控制权。另请参阅授权规范中的 信任策略,以及 客户端 ID 元数据文档规范中的 第 6.4 节第 6.8 节, 以了解更多详情。

范围最小化

糟糕的范围设计会增加令牌被盗用后的影响,提升用户 操作摩擦,并使审计追踪变得模糊。

攻击描述

攻击者通过日志泄露、内存抓取或本地 拦截获得了一个携带广泛范围(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 客户端通用性的特点,因为它们通常缺乏领域特定知识,无法对单个范围的选择做出明智决定。 请求所有可用范围使授权服务器和终端用户能够在同意过程中确定适当的权限,同时遵循最小权限原则,并尽量减少用户摩擦。
跨操作的范围累积是客户端的责任。客户端 SHOULD 在发起重新授权时计算先前请求的范围与新 质询范围的并集,如 Step-Up Authorization Flow 所述。 这使服务器能够在客户端范围集合方面保持无状态, 同时确保客户端不会丢失先前授予的权限。
层级化范围:某些授权服务器定义了范围层级, 其中较宽泛的范围意味着较窄的范围(例如,一个 admin 范围 覆盖 read)。在累积范围时,客户端的并集可能 包含语义上冗余的条目。例如,先前已授予的广泛范围可能会 被一个更窄、但它已隐含包含的范围所质询。客户端无需按层级去重;授权服务器通常会在令牌签发时规范化此类冗余。服务器在判断令牌对某项操作是否足够时, 需要考虑层级关系,但这不会影响它们在质询中发出的范围。

常见错误

  • scopes_supported 中发布所有可能的范围
  • 使用通配符或大而全的范围(*allfull-access
  • 为预先规避未来提示而捆绑无关权限
  • 每次质询都返回整个范围目录
  • 在不进行版本管理的情况下静默更改范围语义
  • 在缺少服务器端授权逻辑的情况下,仅将令牌中声称的范围视为足够
正确的最小化可限制泄露影响、提升审计 清晰度,并减少同意流程的反复出现。