MCP认证与授权
4485 字约 15 分钟
AIAgentMCP安全
2026-07-24
MCP 认证与授权是 MCP 安全体系的核心环节。认证(Authentication)解决"你是谁",授权(Authorization)解决"你可以做什么"。两者不可混为一谈。
一、基本定义
认证(Authentication)—— 你是谁
认证是验证请求方身份的过程。在 MCP 场景中,认证需要回答:
- 发起请求的 Client 来自哪个应用?
- 该请求背后的用户是谁?
- 对端的 Server 是否是其声称的那个 Server?
授权(Authorization)—— 你可以做什么
授权是在身份已确认的前提下,决定该身份能执行哪些操作:
- 该用户是否可以调用这个 Tool?
- 该 Client 是否可以读取这个 Resource?
- 该 Server 是否可以代用户执行写入操作?
不要合并成"鉴权"
中文语境中常把认证和授权合并称为"鉴权",这在工程实践中会导致严重问题:
- 认证和授权的实现机制完全不同(OAuth 流程 vs 权限策略引擎)
- 失败时的处理方式不同(401 vs 403)
- 审计需求不同(登录日志 vs 操作日志)
- 安全团队需要分别评估两者的风险
在 MCP 系统设计和文档中,始终将认证和授权分开讨论。
二、为什么 MCP 的认证和授权特别复杂
MCP 的 Host → Client → Server 三层架构引入了多重身份和信任边界,使认证和授权比传统 API 调用更复杂:
| 复杂性来源 | 说明 |
|---|---|
| 身份代理链 | 用户 → Host → Client → Server → 外部系统,每一步都可能涉及身份传递 |
| 多身份类型 | 用户身份、应用身份、Server 身份、服务身份,需要同时管理 |
| 本地 + 远程混合 | stdio 本地 Server 和 HTTP 远程 Server 的认证模式完全不同 |
| 模型作为决策者 | LLM 决定调用哪个 Tool,但 LLM 本身不参与认证,需要 Host 代为执行 |
| 能力动态发现 | Server 可能在运行时动态暴露 Tool 和 Resource,权限检查需要跟上 |
| 跨 Server 编排 | 一个任务可能需要多个 Server 协作,权限模型需要覆盖多 Server 场景 |
三、身份类型
3.1 用户身份(User Identity)
用户是使用 Host 应用的真实人类。用户身份的特点:
- 通过 Host 应用的登录系统认证(如 SSO、账号密码)
- 用户身份需要通过 MCP 传递给 Server,以便 Server 做权限判断
- MCP 2025 规范通过 OAuth 2.1 实现了用户身份的标准化传递
关键问题:用户是否知道、是否同意某个 Server 正在以其身份执行操作?
3.2 Client 身份(Client / Application Identity)
Client 是 Host 内部的协议实例,代表 Host 应用本身。Client 身份的特点:
- 通常通过 OAuth
client_id标识 - Client 身份用于 Server 识别调用来源
- 同一个 Host 应用的所有 Client 共享相同的
client_id - Client 身份不等于用户身份——应用有权调用 ≠ 用户有权调用
3.3 Server 身份
Server 是 MCP 协议的另一端,也需要被验证:
- Client 需要确认对端 Server 是其声明的那个 Server
- 远程 Server 通过 TLS 证书和 OAuth 注册元数据验证身份
- 本地 Server 通过进程路径、可执行文件签名验证
- 恶意 Server 可以返回虚假的工具描述或注入内容(参见 MCP安全边界)
3.4 服务身份(Service Account)
当 Server 需要以后台方式访问外部系统时,使用服务身份:
- Server 访问数据库、API 等外部系统时使用的非人类身份
- 通常通过 API Key 或 Service Account Token 认证
- 服务身份的权限应该遵循最小权限原则
- 服务身份没有"用户确认"环节,风险更高
四、认证方式
4.1 OAuth 2.0 / OAuth 2.1
MCP 2025 规范正式引入了基于 OAuth 2.1 的认证机制,这是远程 Server 的标准认证方式。
OAuth 2.1 的核心要求:
- 必须使用 PKCE(Proof Key for Code Exchange),不使用隐式授权(Implicit Grant)
- 使用授权码流程(Authorization Code Flow)
- Token 必须支持刷新和撤销
- Server 必须发布 OAuth 授权服务器元数据(RFC 8414)
MCP 使用 OAuth 的方式:
- Client 在连接远程 Server 时,Server 通过
401 Unauthorized响应告知认证需求 - Server 在响应中提供
WWW-Authenticate头,指向 OAuth 授权服务器 - Client 引导用户完成授权流程,获取 Access Token
- Client 在后续请求中携带 Bearer Token
4.2 API Key
API Key 是最简单的认证方式,适合开发阶段和内部工具:
- Server 在配置中接受预设的 API Key
- Client 在请求头中携带 Key(如
X-API-Key: xxx或Authorization: Bearer xxx) - 优点:实现简单,无需交互式授权
- 缺点:Key 泄露风险高,无法传递用户身份,缺少细粒度权限控制
注意:API Key 无法替代 OAuth——它只能认证 Client 身份,无法传递用户身份。
4.3 Token(短期令牌)
短期 Token 通常由认证服务签发,具有有限的有效期:
- Access Token:短期有效(通常 15 分钟到 1 小时),用于请求认证
- Refresh Token:长期有效,用于获取新的 Access Token
- ID Token(OIDC):包含用户身份信息的 JWT
- Token 应该在安全存储中保管,不暴露到日志或错误信息中
4.4 本地凭证
本地 Server 通常通过本地机制获取凭证:
- 环境变量(如
GITHUB_TOKEN、DATABASE_URL) - 配置文件(如
~/.config/server/credentials.json) - 系统 Keychain(如 macOS Keychain、Windows Credential Manager)
- 本地文件(如
~/.aws/credentials)
本地凭证通过 Host 配置传递给 Server:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}4.5 短期凭证 vs 长期凭证
| 特性 | 短期凭证 | 长期凭证 |
|---|---|---|
| 有效期 | 分钟到小时 | 月到年 |
| 泄露影响 | 有限 | 严重 |
| 使用场景 | 用户交互场景 | 服务间调用 |
| 刷新机制 | 需要 Token 刷新 | 手动轮换 |
| 典型形式 | OAuth Access Token | API Key、Service Account Key |
4.6 凭证轮换
凭证轮换是持续安全运营的一部分:
- API Key 应该定期轮换(建议 90 天)
- OAuth Refresh Token 应支持轮换(Refresh Token Rotation)
- 轮换期间应该支持新旧凭证短暂共存
- 轮换后旧凭证必须立即失效
- 自动化轮换优于手动轮换
五、授权模型
5.1 权限范围(Scope)
OAuth Scope 定义了 Client 可以访问的资源范围:
tools:read:列出可用工具tools:execute:调用工具resources:read:读取资源resources:write:修改资源- 自定义 Scope 由 Server 定义
MCP 规范目前没有定义标准 Scope 列表,Scope 的命名和粒度由 Server 实现者决定。
5.2 用户委托(User Delegation)
MCP 的核心设计模式之一是用户委托:
- 用户通过 Host 应用授权 Client 访问 Server
- 用户的权限通过 OAuth Token 传递给 Server
- Server 根据 Token 中的权限信息判断是否允许操作
- Host 可以在用户界面上展示授权确认对话框
5.3 多租户(Multi-tenancy)
当 MCP Server 服务多个用户或组织时,需要考虑多租户隔离:
- 每个租户有独立的权限配置
- 数据访问必须按租户隔离
- OAuth Token 中应包含租户标识
- Server 在处理请求时必须验证请求者与租户的归属关系
5.4 RBAC(基于角色的访问控制)
RBAC 将权限分配给角色,再将角色分配给用户:
- 角色示例:
admin、developer、viewer - 每个角色对应不同的 Tool 和 Resource 访问权限
- 适合组织结构稳定的团队
- Server 根据用户角色过滤可用的 Tool 和 Resource 列表
5.5 ABAC(基于属性的访问控制)
ABAC 根据请求的动态属性做出授权决策:
- 属性来源:用户身份、请求时间、IP 地址、资源类型、操作类型
- 策略示例:
allow if user.department == "engineering" AND time.hour < 18 - 适合权限需求复杂、动态变化的场景
- 实现成本高于 RBAC,但灵活性更强
六、本地 Server 的认证
本地 Server(通过 stdio 传输)的认证有其特殊性:
依赖本地进程信任
- 本地 Server 由 Host 直接启动为子进程
- 信任基础是"本地进程可信"——用户主动安装了该 Server
- 不需要网络层的认证(没有 HTTP 请求)
- 但 Server 的行为仍需受约束
文件系统权限
- 本地 Server 继承启动进程的文件系统权限
- 通过限定工作目录和允许访问的路径来控制权限
- 操作系统级别的用户权限是第一道防线
环境变量传递凭证
- 本地凭证通过环境变量传递给 Server 进程
- Host 的配置文件管理这些环境变量
- 凭证不应该出现在命令行参数中(进程列表可见)
本地 Server 不等于无安全风险。恶意或存在漏洞的本地 Server 仍然可能:读取超出授权范围的文件、泄露环境变量中的凭证、执行非预期的操作。参见 MCP安全边界。
七、远程 Server 的认证
远程 Server(通过 HTTP/SSE 传输)需要完整的认证流程。
OAuth 2.1 授权码流程
MCP 2025 规范中远程 Server 的标准认证流程:
- Client 向 Server 发送请求
- Server 返回
401 Unauthorized,附带WWW-Authenticate头,包含授权服务器地址 - Client 发现授权服务器的元数据(
.well-known/oauth-authorization-server) - Client 动态注册(RFC 7591)或使用已注册的
client_id - Client 启动授权码流程,生成 PKCE 挑战
- 用户在浏览器中完成授权
- Client 用授权码换取 Access Token
- Client 在后续请求中携带 Bearer Token
PKCE(Proof Key for Code Exchange)
PKCE 防止授权码被拦截:
- Client 生成随机
code_verifier - 计算
code_challenge = SHA256(code_verifier) - 授权请求时发送
code_challenge - 换取 Token 时发送
code_verifier - 授权服务器验证两者匹配后才签发 Token
Token 刷新
- Access Token 过期时,Client 使用 Refresh Token 获取新的 Access Token
- 刷新过程中 Client 不需要用户重新授权
- Refresh Token 应该安全存储(如系统 Keychain)
- 授权服务器可以撤销 Refresh Token(用户注销、安全事件等)
OAuth 流程时序图
八、Server 间信任
当多个 MCP Server 需要协作时,信任关系变得更加复杂:
- 直接信任:Server A 信任 Server B 的签名或 Token
- 共同信任的授权服务器:两个 Server 信任同一个 OAuth 授权服务器签发的 Token
- Token 传递:用户的 OAuth Token 通过 Server A 传递给 Server B(需要 Token 的 Scope 覆盖两个 Server)
- 委托链:Server A 代表用户调用 Server B,需要委托机制(如 Token Exchange,RFC 8693)
关键原则:信任不应该隐式传递。Server A 被信任不等于 Server B 也被信任。
九、凭证管理最佳实践
不在代码中硬编码
# ❌ 错误
const API_KEY = "sk-1234567890abcdef"
# ✅ 正确
const API_KEY = process.env.SERVER_API_KEY使用 Secret Manager
- 生产环境使用 AWS Secrets Manager、HashiCorp Vault、GCP Secret Manager 等
- 开发环境使用本地 Keychain 或加密配置文件
- Secret Manager 提供审计日志、自动轮换、细粒度访问控制
定期轮换
- API Key:每 90 天轮换
- OAuth Client Secret:每 180 天轮换
- 数据库凭证:按安全等级设定轮换周期
- 自动化轮换脚本应该在旧凭证失效前生成新凭证
最小权限
- 每个 Server 只获取其必需的最小权限
- Token 的 Scope 不应该超过实际需要的范围
- 服务账号不应该有管理员权限
- 定期审查权限配置,清理不再需要的权限
凭证撤销
- 支持主动撤销凭证(用户注销、安全事件、员工离职)
- OAuth 授权服务器应该提供 Token Revocation 端点(RFC 7009)
- 撤销应该立即生效
- 撤销后应该通知相关方
十、MCP 规范中的认证演进
| 阶段 | 认证方式 | 特点 |
|---|---|---|
| 2024 年初始版本 | 无标准认证 | Server 自行实现,Client 各自适配 |
| 2025 年规范更新 | OAuth 2.1(远程 Server) | 标准化认证流程,引入 PKCE、动态客户端注册 |
| 持续演进 | 更细粒度的权限模型 | 标准 Scope 定义、委托机制、多 Server 认证编排 |
关键变化:2025 年 OAuth 2.1 的引入是 MCP 认证体系的里程碑。在此之前,每个 Server 实现自己的认证方式,导致 Client 需要针对每个 Server 适配不同的认证逻辑。OAuth 2.1 标准化了这一过程。
十一、设计原则
- 认证和授权必须分离:实现、审计、故障排查都是独立的
- 默认拒绝:未认证或未授权的请求一律拒绝
- 用户知情同意:涉及敏感操作的授权必须经过用户确认
- 最小权限:每个身份只获得完成其任务所需的最小权限
- 凭证零暴露:凭证不出现在日志、URL、错误信息中
- 可审计:所有认证和授权事件都应该有日志
- 优雅降级:认证服务不可用时,系统应该安全降级而非完全崩溃
- 纵深防御:不依赖单一认证机制,多层验证
十二、常见误区
| 误区 | 正确理解 |
|---|---|
| "认证和授权是一回事" | 认证是身份验证,授权是权限控制,两者机制和实现完全不同 |
| "本地 Server 不需要安全" | 本地 Server 也需要权限控制,防止越权访问 |
| "API Key 就够了" | API Key 无法传递用户身份,无法做细粒度权限控制 |
| "用户登录了 Host 就等于授权了所有 Server" | 每个 Server 需要独立授权,用户应该能单独撤销 |
| "Token 有效期越长越好" | Token 有效期越短,泄露后的影响越小 |
| "Server 返回的数据天然可信" | Server 返回内容可能包含提示注入,参见 MCP安全边界 |
| "OAuth 太复杂,能不用就不用" | 远程 Server 必须使用 OAuth,这是安全的基本要求 |
十三、实践检查清单
认证
授权
凭证管理
审计
十四、与其他概念的关系
- MCP安全边界:认证与授权是安全边界的核心组成部分
- MCP架构总览:三层架构决定了认证和授权的复杂性
- MCP基础:MCP 的基本概念是理解认证授权的前提
- MCP协议生命周期:认证发生在协议初始化和连接维护阶段
- MCP通信与传输:不同传输方式的认证机制不同
- MCP Client设计:Client 需要实现 OAuth 流程管理
- MCP Server设计:Server 需要实现认证验证和权限检查
- MCP与Agent协作:Agent 场景下的身份传递和委托
十五、适用边界
适用:
- 远程 MCP Server 的认证设计
- 本地 MCP Server 的凭证管理
- 多 Server 场景下的权限规划
- 企业级 MCP 部署的安全合规
- MCP Server 开发中的权限控制实现
不适用:
- Host 应用自身的用户登录系统(由 Host 实现)
- 网络传输层加密(TLS 配置,属于传输层安全)
- 数据库层面的访问控制(由数据库自身管理)
- 操作系统级别的进程隔离(由操作系统管理)