自主 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 身份认证安全的新架构模式。
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)已经成为连接 LLM 与外部数据源及工具的一项标准。它允许 Agent 通过标准化的 JSON-RPC 接口,发现并使用能够提供上下文的“server”,例如数据库、文件系统或 API。MCP 简化了集成,却也带来了传统 API 交互中不存在的新型安全风险。
MCP 依赖工具定义,即描述工具用途及其所接受参数的 JSON schema。Agent 会根据这些定义决定调用哪些工具。如果某个 MCP server 遭到入侵或本身就是恶意的,它便可以提供误导性的工具定义。
例如,某个 MCP server 可能定义一个看似安全的 read_file 工具,但它实际上还包含一个隐藏参数 send_to_external_server。这个参数虽然没有出现在主要描述中,后端却仍然接受它。Agent 因为信任该 schema,可能会在无意间把敏感数据发送到不受信任的端点。这是一种“上下文投毒”:Agent 对工具行为的理解,与工具实际执行的操作产生了偏差。
MCP server 经常直接返回底层系统的原始数据。如果数据库 MCP server 返回的结果集中意外包含凭证、Personally Identifiable Information(PII)或内部网络拓扑,这些信息就会进入 Agent 的上下文窗口。一旦进入上下文窗口,这些数据可能会:
被意外包含在 Agent 的下一次工具调用中,例如把 secret key 复制到 commit message 里。
如果 Agent 所使用的 LLM Provider 会记录 prompt 和响应,这些数据就可能遭到外泄。
被恶意 Agent 用来实施进一步的未授权操作。
传统 API Gateway 会根据状态码或简单的正则表达式过滤响应。MCP 缺少标准化的响应过滤层,因此数据清理的责任落在客户端,也就是 Agent 身上,而这往往超出了 LLM 的能力范围。
MCP server 可以暴露带有副作用的工具,例如 deploy_code 和 delete_resource。这里的安全风险在于动态权限范围提升。Agent 最初可能仅拥有文件系统的只读权限,但如果它能通过串联多个只读工具推断出路径结构,之后就可能利用另一个定义宽松的工具向该路径写入内容。
在 MCP 中,工具通常是在运行时动态发现的。Agent 可能发现一个能够授予写入权限的新工具,从而导致系统管理员未曾预料的意外权限提升。
目前保护 Agent 安全的方法严重依赖静态 token、API key 和环境变量。对于 Autonomous Agent 而言,这些方法存在三个根本性缺陷:
当 Agent 使用静态 API key 时,所有操作都会归属于该 key。系统无法区分由正常 Agent 执行的合法操作,与由已被入侵的 Agent 执行的恶意操作。如果缺少细粒度、按任务记录的审计机制,事件响应就只能被动进行,而且几乎是在盲目处理。
如前所述,Agent 的需求是动态变化的。拥有广泛权限的静态 token 不安全;权限过窄的静态 token 又无法发挥作用。现有机制无法根据 Agent 当前的任务,动态授予 token“读取过去一小时内修改过的文件”或“仅可写入预发布环境”这样的权限。
Agent 的生命周期很短。为成千上万个临时 Agent 轮换凭证,会带来极高的运维成本。大多数组织不会频繁轮换 Agent 凭证,因此一旦 token 泄露,就可能长期暴露在风险之中。
为了保障 Autonomous Agent 的安全,我们必须从静态、基于身份的认证方式,转向动态、基于策略的授权方式。这需要三项关键的架构调整:
系统不应向 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 会自动过期。
授权决策应由中心化的策略引擎作出,而不应嵌入应用程序代码。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,也无法执行未获授权的操作。
为了保障 MCP 层本身的安全,我们需要实施专门的控制措施:
工具定义验证:客户端应在执行 MCP 工具之前,对照已知可信的 schema 验证工具定义。任何偏离预期 schema 的情况都应被标记。
响应清理:MCP server 应与内容安全策略引擎集成,在向 Agent 返回响应之前完成清理,移除 secret、PII 或内部 IP 等敏感数据。
沙箱化执行:MCP server 应在权限最小化的隔离环境中运行,例如 container 或 sandbox。它们不应直接访问生产数据库或生产文件系统。
下面来看一个 JIT 凭证的实际实现:MCP server 使用 Python 和 fastapi framework,token 处理使用 pyjwt。
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..."}
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 泄露,它也会迅速过期,从而限制爆炸半径。
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。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。