简介

目的和范围

本文档为模型上下文协议(MCP)提供了安全方面的考量,是对MCP授权规范的补充。本文档指出了特定于MCP实现的安全风险、攻击向量和最佳实践。 本文档的主要受众包括实现MCP授权流程的开发人员、MCP服务器运营商以及评估基于MCP的系统的安全专业人员。本文档应与MCP授权规范和OAuth 2.0 安全最佳实践一同阅读。

攻击与缓解措施

本节详细描述了针对MCP实现的攻击,并提出了可能的对策。

糊涂代理问题

攻击者可以利用代理其他资源服务器的MCP服务器,制造“糊涂代理”漏洞。

术语

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

架构和攻击流程

正常的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。

缓解措施

使用静态客户端ID的MCP代理服务器在转发到第三方授权服务器(可能需要额外的同意)之前,必须为每个动态注册的客户端获取用户同意。

令牌直通

“令牌直通”是一种反模式,即MCP服务器接受来自MCP客户端的令牌,而不验证这些令牌是否是正确颁发*给该MCP服务器*的,并将其“直通”给下游API。

风险

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

缓解措施

MCP服务器绝不能接受任何未明确为其颁发的令牌。

会话劫持

会话劫持是一种攻击向量,即服务器向客户端提供一个会话ID,而未经授权方能够获取并使用该会话ID来冒充原始客户端,并代表其执行未经授权的操作。

会话劫持提示注入

会话劫持身份冒充

攻击描述

当您有多个处理MCP请求的有状态HTTP服务器时,可能会出现以下攻击向量: 会话劫持提示注入
  1. 客户端连接到服务器A并接收一个会话ID。
  2. 攻击者获取一个已有的会话ID,并向服务器B发送一个带有该会话ID的恶意事件。
    • 当服务器支持重新投递/可恢复流时,在收到响应前故意终止请求,可能导致原始客户端通过GET请求服务器发送事件来恢复该请求。
    • 如果某个服务器因工具调用(如 notifications/tools/list_changed)而启动服务器发送事件,且有可能影响服务器提供的工具,则客户端最终可能会获得一些其并不知道已启用的工具。
  3. 服务器B将该事件(与会话ID关联)放入一个共享队列中。
  4. 服务器A使用会话ID从队列中轮询事件,并检索到恶意负载。
  5. 服务器A将恶意负载作为异步或恢复的响应发送给客户端。
  6. 客户端接收并执行该恶意负载,可能导致被攻破。
会话劫持身份冒充
  1. MCP客户端向MCP服务器进行身份验证,创建一个持久的会话ID。
  2. 攻击者获取该会话ID。
  3. 攻击者使用该会话ID向MCP服务器发出调用。
  4. MCP服务器不检查额外的授权,并将攻击者视为合法用户,从而允许未经授权的访问或操作。

缓解措施

为防止会话劫持和事件注入攻击,应实施以下缓解措施: 实现授权的MCP服务器必须验证所有入站请求。MCP服务器绝不能使用会话进行身份验证。 MCP服务器必须使用安全的、非确定性的会话ID。生成的会话ID(例如UUID)使用安全的随机数生成器。避免使用可被攻击者猜测的可预测或顺序会话标识符。轮换或使会话ID过期也可以降低风险。 MCP服务器将话ID与用户特定信息绑定。在存储或传输与会话相关的数据(例如,在队列中)时,将话ID与授权用户唯一的信息(如其内部用户ID)结合起来。使用类似 <user_id>:<session_id> 的密钥格式。这确保了即使攻击者猜到了会话ID,他们也无法冒充其他用户,因为用户ID是从用户令牌中派生的,而不是由客户端提供的。 MCP服务器可以有选择地利用其他唯一标识符。