安全最佳实践
1. 介绍
目的和范围
本文档为模型上下文协议(MCP)提供安全考虑,作为 MCP 授权规范的补充。本文档识别了 MCP 实现特有的安全风险、攻击向量和最佳实践。
本文档的主要受众包括实现 MCP 授权流程的开发人员、MCP 服务器运营者,以及评估基于 MCP 系统的安全专业人员。本文档应与 MCP 授权规范和 OAuth 2.0 安全最佳实践 一起阅读。
2. 攻击和缓解措施
本节详细描述了对 MCP 实现的攻击以及潜在的对策。
混淆代理问题
攻击者可以利用代理其他资源服务器的 MCP 服务器,创建"混淆代理"漏洞。
术语
MCP 代理服务器 : 一个将 MCP 客户端连接到第三方 API 的 MCP 服务器,在委托操作和充当第三方 API 服务器的单个 OAuth 客户端的同时提供 MCP 功能。
第三方授权服务器 : 保护第三方 API 的授权服务器。它可能缺乏动态客户端注册支持,要求 MCP 代理对所有请求使用静态客户端 ID。
第三方 API : 提供实际 API 功能的受保护资源服务器。访问此 API 需要由第三方授权服务器颁发的令牌。
静态客户端 ID : MCP 代理服务器与第三方授权服务器通信时使用的固定 OAuth 2.0 客户端标识符。此客户端 ID 指的是充当第三方 API 客户端的 MCP 服务器。无论哪个 MCP 客户端发起请求,所有 MCP 服务器到第三方 API 的交互都是相同的值。
架构和攻击流程
正常的 OAuth 代理使用(保留用户同意)
恶意 OAuth 代理使用(跳过用户同意)
攻击描述
当 MCP 代理服务器使用静态客户端 ID 与不支持动态客户端注册的第三方授权服务器进行身份验证时,可能发生以下攻击:
- 用户通过 MCP 代理服务器正常进行身份验证以访问第三方 API
- 在此流程中,第三方授权服务器在用户代理上设置一个 Cookie,表示对静态客户端 ID 的同意
- 攻击者稍后向用户发送一个恶意链接,包含一个精心制作的授权请求,其中包含恶意重定向 URI 以及新的动态注册客户端 ID
- 当用户点击链接时,他们的浏览器仍然具有来自先前合法请求的同意 Cookie
- 第三方授权服务器检测到 Cookie 并跳过同意屏幕
- MCP 授权码被重定向到攻击者的服务器(在动态客户端注册期间在精心制作的 redirect_uri 中指定)
- 攻击者在没有用户明确批准的情况下将被盗的授权码交换为 MCP 服务器的访问令牌
- 攻击者现在可以作为被攻破的用户访问第三方 API
缓解措施
使用静态客户端 ID 的 MCP 代理服务器 必须 在转发到第三方授权服务器之前为每个动态注册的客户端获得用户同意(这可能需要额外的同意)。
令牌传递
"令牌传递"是一种反模式,MCP 服务器接受来自 MCP 客户端的令牌,而不验证令牌是否正确颁发给 MCP 服务器,并将它们"传递"给下游 API。
风险
令牌传递在 授权规范 中被明确禁止,因为它引入了许多安全风险,包括:
- 安全控制规避
- MCP 服务器或下游 API 可能实现重要的安全控制,如速率限制、请求验证或流量监控,这些控制依赖于令牌受众或其他凭据约束。如果客户端可以直接获取和使用令牌与下游 API,而 MCP 服务器没有正确验证它们或确保令牌为正确的服务颁发,他们会绕过这些控制。
- 问责和审计追踪问题
- 当客户端使用对 MCP 服务器可能不透明的上游颁发的访问令牌进行调用时,MCP 服务器将无法识别或区分 MCP 客户端。
- 下游资源服务器的日志可能显示似乎来自不同来源和不同身份的请求,而不是实际转发令牌的 MCP 服务器。
- 这两个因素都使事件调查、控制和审计变得更加困难。
- 如果 MCP 服务器在不验证其声明(例如,角色、特权或受众)或其他元数据的情况下传递令牌,拥有被盗令牌的恶意行为者可以使用服务器作为数据泄露的代理。
- 信任边界问题
- 下游资源服务器对特定实体授予信任。这种信任可能包括对来源或客户端行为模式的假设。破坏这种信任边界可能导致意外问题。
- 如果令牌被多个服务接受而没有适当的验证,攻击者攻破一个服务可以使用令牌访问其他连接的服务。
- 未来兼容性风险
- 即使 MCP 服务器今天从"纯代理"开始,它可能需要稍后添加安全控制。从适当的令牌受众分离开始使得更容易发展安全模型。
缓解措施
MCP 服务器 不得 接受任何未明确为 MCP 服务器颁发的令牌。
会话劫持
会话劫持是一种攻击向量,客户端由服务器提供会话 ID,未经授权的一方能够获得并使用相同的会话 ID 来冒充原始客户端并代表其执行未经授权的操作。
会话劫持提示注入
会话劫持冒充
攻击描述
当您有多个处理 MCP 请求的有状态 HTTP 服务器时,可能出现以下攻击向量:
会话劫持提示注入
客户端连接到 服务器 A 并接收会话 ID。
攻击者获得现有会话 ID 并向 服务器 B 发送带有所述会话 ID 的恶意事件。
- 当服务器支持 重新传递/可恢复流 时,在接收响应之前故意终止请求可能导致它通过原始客户端的服务器发送事件的 GET 请求恢复。
- 如果特定服务器由于工具调用(如
notifications/tools/list_changed
)而启动服务器发送事件,其中可能影响服务器提供的工具,客户端可能最终获得他们不知道已启用的工具。
服务器 B 将事件(与会话 ID 关联)排队到共享队列中。
服务器 A 使用会话 ID 轮询队列中的事件并检索恶意负载。
服务器 A 将恶意负载作为异步或恢复响应发送给客户端。
客户端接收并基于恶意负载执行操作,导致潜在的攻破。
会话劫持冒充
- MCP 客户端与 MCP 服务器进行身份验证,创建持久会话 ID。
- 攻击者获得会话 ID。
- 攻击者使用会话 ID 向 MCP 服务器进行调用。
- MCP 服务器不检查额外的授权,将攻击者视为合法用户,允许未经授权的访问或操作。
缓解措施
为了防止会话劫持和事件注入攻击,应实施以下缓解措施:
实现授权的 MCP 服务器 必须 验证所有入站请求。 MCP 服务器 不得 使用会话进行身份验证。
MCP 服务器 必须 使用安全的、非确定性的会话 ID。 生成的会话 ID(例如,UUID)应该 使用安全的随机数生成器。避免可能被攻击者猜测的可预测或顺序会话标识符。轮换或过期会话 ID 也可以降低风险。
MCP 服务器 应该 将会话 ID 绑定到用户特定信息。 在存储或传输会话相关数据(例如,在队列中)时,将会话 ID 与授权用户唯一的信息(如其内部用户 ID)结合。使用 <user_id>:<session_id>
等键格式。这确保即使攻击者猜测到会话 ID,他们也无法冒充另一个用户,因为用户 ID 是从用户令牌派生的,而不是由客户端提供的。
MCP 服务器可以选择性地利用额外的唯一标识符。