Agent 时代的身份认证困局:MCP 安全重思
自主 agent 打破传统 AuthN/AuthZ 模型,MCP 协议带来凭证泄露和权限提升风险,需要重新设计 agent 认证架构。
完整中文译文
最初发布于 tamiz.pro。
Large Language Models(LLM)与软件开发生命周期的集成,已经从被动的代码补全,演进到能够读取代码仓库、运行测试和部署基础设施的主动式 Autonomous Agent。这一转变带来了一个传统网络安全模型难以应对的关键架构漏洞:Agent-as-a-User(Agent 即用户)问题。
数十年来,身份认证与授权(AuthN/AuthZ)一直围绕人类操作者或拥有静态权限范围的长期 Service Account 设计。然而,Autonomous Agent 是动态且依赖上下文的,并且通常需要在严格的 token 预算和时间限制下运行。当这些 Agent 通过 Model Context Protocol(MCP)等协议与外部系统交互时,凭证泄露、权限提升和供应链攻击的攻击面会呈指数级扩大。
本文将剖析 Agent 驱动工作流中现有凭证管理机制的失效模式,分析 MCP 特有的安全影响,并提出一种用于保障 Agent 身份认证安全的新架构模式。
Agent-as-a-User 悖论
Autonomous Dev Tools 的核心矛盾,在于以人为中心的安全模型与以 Agent 为中心的运行需求之间存在错位。传统的 Role-Based Access Control(RBAC)假设用户身份与一组权限之间存在静态映射。例如,“Developer”角色可能拥有 Git 代码仓库的读写权限,以及预发布数据库的只读权限。
然而,Autonomous Agent 并不“是”一名开发者,而是代表开发者执行操作,并且实际执行的任务经常会超出最初的意图。假设有一个 Agent 接到“修复支付服务中的 bug”这一任务。为了有效完成任务,它可能需要:
-
读取生产数据库日志,以复现错误。
-
将代码写入预发布环境。
-
触发部署流水线。
在传统 RBAC 模型中,要授予 Agent 必要的权限,就必须为它提供一个拥有广泛权限的 Service Account。这会造成“God Mode”问题:如果 Agent 遭到入侵,或者产生幻觉并执行恶意操作,例如本应修复查询却删除了数据表,其爆炸半径将极其巨大。反过来,如果把 Agent 的权限限制得过窄,它往往又会变得毫无用处,迫使开发者手动介入,打断整个自动化闭环。
此外,Agent 是临时存在的。它们针对单个任务创建,运行数分钟或数小时,然后终止。为这些短暂存在的实体管理静态凭证,不仅效率低下,而且容易出错。将 API key 硬编码到 Agent prompt 或配置文件中是一个严重漏洞,因为 prompt 经常会被记录、共享或缓存。
Model Context Protocol(MCP)的攻击面
Model Context Protocol(MCP)已经成为连接 LLM 与外部数据源及工具的一项标准。它允许 Agent 通过标准化的 JSON-RPC 接口,发现并使用能够提供上下文的“server”,例如数据库、文件系统或 API。MCP 简化了集成,却也带来了传统 API 交互中不存在的新型安全风险。
1. 通过工具定义实施上下文投毒
MCP 依赖工具定义,即描述工具用途及其所接受参数的 JSON schema。Agent 会根据这些定义决定调用哪些工具。如果某个 MCP server 遭到入侵或本身就是恶意的,它便可以提供误导性的工具定义。
例如,某个 MCP server 可能定义一个看似安全的 read_file 工具,但它实际上还包含一个隐藏参数 send_to_external_server。这个参数虽然没有出现在主要描述中,后端却仍然接受它。Agent 因为信任该 schema,可能会在无意间把敏感数据发送到不受信任的端点。这是一种“上下文投毒”:Agent 对工具行为的理解,与工具实际执行的操作产生了偏差。
2. 工具输出中的凭证泄露
MCP server 经常直接返回底层系统的原始数据。如果数据库 MCP server 返回的结果集中意外包含凭证、Personally Identifiable Information(PII)或内部网络拓扑,这些信息就会进入 Agent 的上下文窗口。一旦进入上下文窗口,这些数据可能会:
-
被意外包含在 Agent 的下一次工具调用中,例如把 secret key 复制到 commit message 里。
-
如果 Agent 所使用的 LLM Provider 会记录 prompt 和响应,这些数据就可能遭到外泄。
-
被恶意 Agent 用来实施进一步的未授权操作。
传统 API Gateway 会根据状态码或简单的正则表达式过滤响应。MCP 缺少标准化的响应过滤层,因此数据清理的责任落在客户端,也就是 Agent 身上,而这往往超出了 LLM 的能力范围。
3. 动态权限范围提升
MCP server 可以暴露带有副作用的工具,例如 deploy_code 和 delete_resource。这里的安全风险在于动态权限范围提升。Agent 最初可能仅拥有文件系统的只读权限,但如果它能通过串联多个只读工具推断出路径结构,之后就可能利用另一个定义宽松的工具向该路径写入内容。
在 MCP 中,工具通常是在运行时动态发现的。Agent 可能发现一个能够授予写入权限的新工具,从而导致系统管理员未曾预料的意外权限提升。
为什么传统凭证管理会失效
目前保护 Agent 安全的方法严重依赖静态 token、API key 和环境变量。对于 Autonomous Agent 而言,这些方法存在三个根本性缺陷:
1. 缺乏细粒度审计
当 Agent 使用静态 API key 时,所有操作都会归属于该 key。系统无法区分由正常 Agent 执行的合法操作,与由已被入侵的 Agent 执行的恶意操作。如果缺少细粒度、按任务记录的审计机制,事件响应就只能被动进行,而且几乎是在盲目处理。
2. 静态权限与动态需求之间的矛盾
如前所述,Agent 的需求是动态变化的。拥有广泛权限的静态 token 不安全;权限过窄的静态 token 又无法发挥作用。现有机制无法根据 Agent 当前的任务,动态授予 token“读取过去一小时内修改过的文件”或“仅可写入预发布环境”这样的权限。
3. 凭证轮换与生命周期
Agent 的生命周期很短。为成千上万个临时 Agent 轮换凭证,会带来极高的运维成本。大多数组织不会频繁轮换 Agent 凭证,因此一旦 token 泄露,就可能长期暴露在风险之中。
新范式:Just-in-Time(JIT)凭证与 Policy-as-Code
为了保障 Autonomous Agent 的安全,我们必须从静态、基于身份的认证方式,转向动态、基于策略的授权方式。这需要三项关键的架构调整:
1. Just-in-Time(JIT)凭证签发
系统不应向 Agent 提供长期有效的 token,而应签发范围限定于具体任务、有效期覆盖 Agent 生命周期的 JIT 凭证。可以通过以下方式实现:
-
短期 token(JWT):在数分钟或数小时后过期的 token。
-
OAuth 2.0 Token Exchange:Agent 向 Identity Provider 请求 token,并明确指定自己所需的资源和操作。
-
SPIFFE/SPIRE:在 Cloud Native 环境中,Agent 可以使用 SPIFFE ID 与其他服务进行身份认证,无须硬编码 secret,从而实现安全的服务身份管理。
例如,一个负责向预发布环境部署修复版本的 Agent,会向 Identity Provider(IdP)请求 JWT。IdP 签发一个权限范围仅限于 staging:deploy、有效期为 15 分钟的 token。Agent 使用该 token 调用部署 API。任务完成后,token 会自动过期。
2. 使用 OPA(Open Policy Agent)实现 Policy-as-Code
授权决策应由中心化的策略引擎作出,而不应嵌入应用程序代码。OPA 是实现这一目标的常用工具。策略使用 Rego 定义,并在运行时进行求值。
对于 MCP server,可以使用 sidecar proxy 拦截所有 MCP 工具调用。在工具执行前,sidecar 会根据 OPA 策略检查 Agent 的 token。策略可以强制执行以下规则:
-
“只有拥有
deployer角色的 Agent 才能调用deploy_code。” -
“只有正在处理
project-alpha的 Agent 才能访问database-alpha。” -
“在维护窗口以外,任何 Agent 都不得调用
delete_resource。”
这能确保 Agent 即便持有有效 token,也无法执行未获授权的操作。
3. MCP 专用安全控制
为了保障 MCP 层本身的安全,我们需要实施专门的控制措施:
-
工具定义验证:客户端应在执行 MCP 工具之前,对照已知可信的 schema 验证工具定义。任何偏离预期 schema 的情况都应被标记。
-
响应清理:MCP server 应与内容安全策略引擎集成,在向 Agent 返回响应之前完成清理,移除 secret、PII 或内部 IP 等敏感数据。
-
沙箱化执行:MCP server 应在权限最小化的隔离环境中运行,例如 container 或 sandbox。它们不应直接访问生产数据库或生产文件系统。
实现安全的 Agent Auth:一个实践示例
下面来看一个 JIT 凭证的实际实现:MCP server 使用 Python 和 fastapi framework,token 处理使用 pyjwt。
第 1 步:定义带有 JWT 验证的 MCP Server
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
import datetime
app = FastAPI()
security = HTTPBearer()
# Mock secret key (in production, use environment variables)
SECRET_KEY = "super-secret-key-change-in-production"
ALGORITHM = "HS256"
# Mock function to verify JWT
def verify_token(token: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
# MCP Tool Definition
@app.get("/mcp/tools")
def get_tools():
return {
"tools": [
{
"name": "read_file",
"description": "Reads the content of a file",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string"}
},
"required": ["path"]
}
}
]
}
# MCP Tool Execution with Auth
@app.post("/mcp/call_tool")
def call_tool(credentials: HTTPAuthorizationCredentials = Depends(security)):
# Validate the JWT
payload = verify_token(credentials.credentials)
# Check if the agent has permission to call 'read_file'
if "read_file" not in payload.get("scopes", []):
raise HTTPException(status_code=403, detail="Insufficient permissions")
# In a real implementation, you would parse the request body
# and execute the tool safely here.
return {"result": "File content..."}
第 2 步:客户端请求 Token
Agent(客户端)应在发起 MCP 调用之前,先向 IdP 请求 token。
import requests
import jwt
# Agent requests a token from IdP
response = requests.post(
"https://idp.example.com/oauth/token",
data={
"grant_type": "client_credentials",
"client_id": "agent-123",
"client_secret": "agent-secret",
"scope": "read_file deploy_code"
}
)
token = response.json()["access_token"]
# Use the token to call the MCP server
headers = {"Authorization": f"Bearer {token}"}
response = requests.post("http://mcp-server.example.com/mcp/call_tool", headers=headers)
这种模式可以确保 Agent 只在必要的时间内,拥有完成任务所需的权限。如果 token 泄露,它也会迅速过期,从而限制爆炸半径。
Human-in-the-Loop(HITL)的作用
JIT 凭证和策略引擎虽然能够实现授权自动化,但在高风险场景中,它们无法取代人类监督。对于生产环境部署或数据库 schema 变更等操作,Human-in-the-Loop(HITL)检查点必不可少。
在这种模式下,Agent 会先提出一项操作,例如“我将把 2.1 版本部署到生产环境”。MCP server 或专用 orchestrator 会暂停执行,并向人类审批者发送通知。审批者审查 Agent 的推理过程——这部分内容可以包含在上下文窗口中——然后批准或拒绝该操作。
这不会显著降低开发速度,因为它只会为高风险操作增加一道关卡。同时,它还能提供一条很有价值的审计记录:“Agent X 提出了 Y 操作,Human Z 批准了该操作。”
结论:让安全成为一等公民
Autonomous Dev Tools 的时代已经到来,而且不会消失。随着 Agent 的能力越来越强,与凭证管理和协议交互相关的安全风险也会不断增长。传统安全模型是为人类和静态系统设计的,已经无法满足这一新现实的需要。
为了保障 Autonomous Agent 的安全,我们必须采用:
-
Just-in-Time Credentials:与 Agent 任务生命周期保持一致的短期、限定权限范围的 token。
-
Policy-as-Code:使用中心化、动态的授权引擎,例如 OPA,实施细粒度权限控制。
-
MCP 专用控制措施:验证工具定义、清理响应,并在沙箱环境中执行。
-
Human-in-the-Loop:为高风险操作设置检查点,确保有人类参与监督。
在 Agent 驱动的开发模式中,安全不能是事后补救措施。它必须被嵌入 Agent、协议及其所交互基础设施的架构之中。通过重新思考凭证管理,并采用动态、基于策略的安全机制,我们可以在不损害系统完整性的前提下,充分释放 Autonomous Agent 的潜力。
常见问题
问:我可以为 Agent 使用现有的 OAuth2 flow 吗?
答:可以。OAuth 2.0 是一个很好的基础,但对于 Machine-to-Machine 身份认证,你应该使用 Client Credentials grant type。请确保签发的 token 有效期较短,并且权限范围严格限定于 Agent 的具体任务。
问:应该如何处理 MCP server 的凭证轮换?
答:使用 HashiCorp Vault 或 AWS Secrets Manager 等 Secrets Management System 存储和轮换凭证。MCP server 应在运行时动态地从 Secrets Manager 获取凭证,而不是将凭证硬编码在代码中。
问:MCP 是否开箱即用地提供安全保障?
答:不是。MCP 是一种协议,而不是安全解决方案。它提供了交互机制,但不会强制实施身份认证或授权。你必须在 MCP 之上实现安全控制,例如 JWT validation、rate limiting 和 response filtering。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。