1. 安全最佳实践介绍 #
1.1 目的与范围 #
本文档为模型上下文协议(MCP)提供了全面的安全考量,作为MCP授权规范的补充。文档详细阐述了MCP实现中特有的安全风险、攻击向量及最佳实践方案。
主要受众包括:
- 实现MCP授权流程的开发者
- MCP服务器运维人员
- 评估基于MCP系统的安全专业人员
重要提示: 阅读本文档时应同时参考MCP授权规范与OAuth 2.0 安全最佳实践。
2. 攻击与缓解措施 #
本节详细描述了针对MCP实现的攻击方式,并提供了相应的应对措施。
2.1 混淆代理问题 #
攻击者可以利用MCP服务器代理其他资源服务器的特性,制造"混淆代理"漏洞。
2.1.1 术语定义 #
MCP代理服务器: 一个连接MCP客户端与第三方API的MCP服务器,在提供MCP功能的同时委托操作,并作为第三方API服务器的单一OAuth客户端。
第三方授权服务器: 保护第三方API的授权服务器。它可能缺乏动态客户端注册支持,需要MCP代理为所有请求使用静态客户端ID。
第三方API: 提供实际API功能的受保护资源服务器。访问此API需要由第三方授权服务器颁发的Access Token。
静态 Client ID: MCP代理服务器与第三方授权服务器通信时使用的固定OAuth 2.0客户端标识符。该Client ID代表MCP服务器作为第三方API的客户端角色。无论请求由哪个MCP客户端发起,所有MCP服务器与第三方API交互时都使用相同的值。
2.1.2 架构与攻击流程 #
2.1.2.1 正常OAuth代理使用方式(保留用户同意) #
在正常的OAuth代理流程中:

- 初始认证流程完成 - 用户通过MCP代理服务器进行身份验证
- 获取用户对第三方服务器的合法授权 - 用户被重定向至第三方授权服务器
- 审查同意屏幕 - 用户查看并确认授权请求
- 将3P代码兑换为3PAccess Token - 第三方授权服务器处理授权码
- 生成MCP授权码 - MCP代理服务器创建自己的授权码
- 兑换代码以获取token等 - 完成整个授权流程
2.1.2.2 恶意OAuth代理使用(绕过用户同意) #
攻击者可以利用以下步骤绕过用户同意:

- 动态注册恶意客户端 - 攻击者注册一个恶意客户端
- 发送恶意链接 - 向用户发送包含精心构造授权请求的链接
- 授权请求 - 用户点击链接,浏览器仍保留着之前合法请求中的同意cookie
- 检测到Cookie,已跳过同意环节 - 第三方授权服务器检测到cookie并跳过同意界面
- 3P授权码 + 重定向至mcp-proxy-server.com - 授权码被重定向到攻击者控制的服务器
- 将3P代码兑换为3PAccess Token - 攻击者处理授权码
- 生成MCP授权码 - 生成MCP授权码
- 重定向至attacker.com并携带MCP授权码 - 授权码被发送到攻击者服务器
- 攻击者冒充用户向MCP服务器发起请求 - 攻击者获得对第三方API的访问权限
2.1.3 攻击描述 #
当MCP代理服务器使用静态客户端ID与不支持动态客户端注册的第三方授权服务器进行身份验证时,可能会出现以下攻击:
- 用户通过MCP代理服务器正常进行身份验证,以访问第三方API。
- 在此流程中,第三方授权服务器会在用户代理上设置一个cookie,表明对静态client ID的许可。
- 随后,攻击者向用户发送一个恶意链接,其中包含精心构造的授权请求,该请求附带了一个恶意的重定向URI以及新动态注册的客户端ID。
- 当用户点击链接时,他们的浏览器仍保留着之前合法请求中的同意cookie。
- 第三方授权服务器检测到cookie并跳过同意界面
- MCP授权码被重定向至攻击者的服务器(该服务器地址在动态客户端注册阶段通过精心构造的重定向URL指定)
- 攻击者在未经用户明确同意的情况下,将被盗的授权码兑换成MCP服务器的访问Access Token。
- 攻击者现在能以被入侵用户的身份访问第三方API。
2.1.4 缓解措施 #
重要要求: 使用静态客户端ID的MCP代理服务器必须在转发至第三方授权服务器之前,需为每个动态注册的客户端获取用户同意(该过程可能需要额外授权)。
2.2 Access Token透传 #
"Token passthrough"是一种反模式,指MCP服务器接受来自MCP客户端的Access Token而不验证这些Access Token是否被正确签发,并将它们"传递"给下游API。
2.2.1 风险 #
Token透传被明确禁止,因为它引入了一系列安全风险,包括:
2.2.1.1 安全控制规避 #
- MCP Server或下游API可能实施了重要的安全控制措施,如速率限制、请求验证或流量监控,这些措施依赖于Access Token受众或其他凭证约束。
- 如果客户端能够直接获取并使用Access Token与下游API交互,而未经MCP服务器正确验证或确保Access Token是为正确的服务颁发的,那么他们将绕过这些控制措施。
2.2.1.2 问责与审计追踪问题 #
- 当客户端使用上游颁发的访问Access Token(该Access Token对MCP Server可能是不透明的)进行调用时,MCP Server将无法识别或区分不同的MCP Client。
- 下游Resource Server的日志可能显示看似来自不同源且身份不同的请求,而非实际转发Access Token的MCP服务器。
- 这两个因素使得事件调查、管控和审计变得更加困难。
- 如果MCP服务器未验证Access Token的声明(例如角色、权限或受众)或其他元数据就直接传递Access Token,持有被盗Access Token的恶意攻击者可能利用该服务器作为数据外泄的代理。
2.2.1.3 信任边界问题 #
- 下游资源服务器对特定实体授予信任。这种信任可能包含对来源或客户端行为模式的假设。打破这一信任边界可能导致意外问题。
- 如果Access Token被多个服务接受而未经过适当验证,攻击者一旦攻破其中一个服务,就能利用该Access Token访问其他关联服务。
2.2.1.4 未来兼容性风险 #
- 即使MCP Server最初仅作为"纯代理"启动,未来也可能需要添加安全控制措施。从一开始就采用适当的Access Token受众分离机制,能让安全模型的演进更加轻松。
2.2.2 缓解措施 #
重要要求: MCP服务器不得接受任何未明确为MCP服务器发行的token。
2.3 会话劫持 #
会话劫持是一种攻击手段,当服务器向客户端提供会话ID时,未经授权的第三方能够获取并使用相同的会话ID,冒充原始客户端并以其名义执行未授权操作。
2.3.1 会话劫持式提示注入 #
当您拥有多个处理MCP请求的有状态HTTP服务器时,可能存在以下攻击途径:
2.3.1.1 攻击流程 #

- 初始化(连接到可流式传输的HTTP服务器) - 客户端连接到服务器A并收到会话ID
- 返回会话ID - 服务器返回会话标识符
- 访问/猜测会话ID - 攻击者获取了现有的会话ID
- 触发事件(恶意负载,使用会话ID) - 攻击者向服务器B发送恶意事件
- 入队事件(按会话ID键控) - 服务器B将事件加入共享队列
- 轮询事件(使用session ID) - 服务器A使用session ID轮询队列
- 事件数据(恶意负载) - 服务器A检索恶意payload
- 异步响应(恶意负载) - 服务器A将恶意负载发送给客户端
- 基于恶意负载的行为 - 客户端接收并执行恶意负载
2.3.1.2 攻击描述 #
- 客户端连接到服务器A并收到一个会话ID。
- 攻击者获取了一个现有的会话ID,并向其发送了一个恶意事件。服务器B使用所述会话ID。
- 当服务器支持重新投递/可恢复流时,主动在接收响应前终止请求可能导致原始客户端通过服务器发送事件的GET请求恢复该连接。
- 如果某个特定服务器因工具调用(如
notifications/tools/list_changed)而发起服务器发送事件(server sent events),在这种情况下,客户端可能会无意中启用他们并不知情的服务器提供的工具。
- 服务器B将事件(关联到会话ID)加入共享队列。
- 服务器A使用session ID轮询队列以获取事件,并检索恶意payload。
- 服务器A将恶意负载作为异步或恢复的响应发送给客户端。
- 客户端接收并执行了恶意负载,可能导致系统被入侵。
2.3.2 会话劫持冒充 #
2.3.2.1 攻击流程 #

- 初始化(登录/身份验证) - MCP客户端与MCP服务器进行认证
- 返回会话ID(已创建持久会话) - 服务器创建持久会话ID
- 访问/猜测会话ID - 攻击者获取了会话ID
- 发起API调用(使用session ID,无需重新认证) - 攻击者利用会话ID向MCP服务器发起调用
- 假设攻击者是客户端(会话劫持) - MCP服务器不会检查额外的授权,并将攻击者视为合法用户
2.3.2.2 攻击描述 #
- MCP客户端与MCP服务器进行认证,创建一个持久会话ID。
- 攻击者获取了会话ID。
- 攻击者利用会话ID向MCP服务器发起调用。
- MCP服务器不会检查额外的授权,并将攻击者视为合法用户,从而允许未经授权的访问或操作。
2.3.3 缓解措施 #
为防止会话劫持和事件注入攻击,应采取以下缓解措施:
重要要求: 实现授权功能的MCP服务器必须验证所有入站请求。MCP Servers不得使用会话进行身份验证。
会话ID安全要求:
- MCP服务器必须使用安全的、非确定性的会话ID。生成的会话ID(例如UUIDs)应该使用安全的随机数生成器。
- 避免使用可预测或连续的会话标识符,以防被攻击者猜中。
- 定期轮换或设置会话ID过期也能降低风险。
会话绑定要求:
- MCP服务器应该将会话ID与用户特定信息绑定。
- 在存储或传输会话相关数据(例如在队列中)时,将会话ID与授权用户的唯一信息(如内部用户ID)结合使用。
- 采用类似以下的键格式:
<user_id>:<session_id> - 这确保了即使攻击者猜中了一个会话ID,也无法冒充其他用户,因为用户ID是从用户Access Token派生的,而非由客户端提供。
- MCP服务器可以选择性地利用额外的唯一标识符。
3. 总结 #
本文档详细介绍了MCP实现中的主要安全风险和相应的缓解措施。作为MCP开发者或运维人员,请务必:
3.1 关键要点 #
混淆代理问题
- 使用静态客户端ID时必须为每个动态注册的客户端获取用户同意
- 避免绕过用户授权流程
Access Token透传
- 严格禁止接受未明确为MCP服务器发行的token
- 实施适当的Access Token验证机制
会话劫持
- 使用安全的、非确定性的会话ID
- 将会话ID与用户特定信息绑定
- 避免仅依赖会话进行身份验证
3.2 最佳实践建议 #
- 实施多层安全控制:不要仅依赖单一安全机制
- 定期安全审计:定期检查和更新安全措施
- 遵循最小权限原则:只授予必要的权限
- 监控异常活动:建立有效的监控和告警机制
- 保持更新:及时更新安全补丁和最佳实践