MCP Server 不是普通的 HTTP API——它暴露的不是"数据",是"能力"(LLM 自主调用的能力)。能力被滥用,比数据泄露更可怕:越权查简历、批量刷接口、被 Prompt 注入带偏。
这篇文章是我们在企业级 MCP 服务上的安全设计:从 Token 鉴权到会话隔离到工具级权限。
一、先认清威胁模型#
| 威胁 |
场景 |
后果 |
| 越权访问 |
无权限用户让 LLM 查了别人的简历 |
数据泄露 |
| 滥用/刷量 |
批量调用高成本工具(ES 检索) |
资源耗尽/成本失控 |
| Prompt 注入 |
工具返回的内容里藏指令,带偏 LLM |
工具被劫持 |
| 凭证泄露 |
Server 的 token 被偷 |
全量权限沦陷 |
| 审计缺失 |
出事后查不到谁调了什么 |
无法追责 |
核心原则:LLM 调用 ≠ 无权限调用。MCP Server 是系统的一部分,要按内部系统的标准上安全。
二、第一道:Token 鉴权#
1
2
3
4
5
6
7
8
|
// 每个调用方(应用/Agent/用户)一个 token
{
"token": "mcp_xxxxxxxx",
"owner": "agent-interviewer",
"scope": ["resume.search", "resume.read"],
"expires": "2026-12-31",
"quota": {"resume.search": 1000, "per_day": true}
}
|
实现(FastMCP 中间件)#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
from fastmcp import FastMCP
from fastmcp.server.middleware import MiddlewareManager
mcp = FastMCP("enterprise-mcp")
@mcp.middleware
async def auth_middleware(request, call_next):
# 1. 取 token(Header: Authorization: Bearer xxx)
token = request.headers.get("authorization", "").replace("Bearer ", "")
# 2. 验 token + scope
perm = verify_token(token)
if not perm:
return {"error": "UNAUTHORIZED", "code": 401}
# 3. 注入上下文(后续工具读取)
request.context = {"user": perm.owner, "scope": perm.scope}
return await call_next(request)
|
三、第二道:工具级权限#
所有用户都能调所有工具?NO。 工具级权限:
1
2
3
4
5
6
7
8
|
@mcp.tool()
def search_resume(query: str, context) -> list:
# 权限检查:只有 interview 作用域能调
if "resume.search" not in context.scope:
return {"error": "PERMISSION_DENIED", "code": 403}
# 数据级权限:只能搜自己有权限的库
db = get_allowed_db(context.owner)
return es_search(db, query)
|
双层权限:
经典错误:只做了工具级,数据级没做——两个面试官都"能调 search_resume",但一个该只能搜 A 库,另一个只能搜 B 库。工具能调 ≠ 数据能看。
四、第三道:会话隔离#
LLM 是共享的,但调用 MCP 的上下文(用户身份)必须隔离:
1
2
3
|
# 会话隔离:token → session → 权限上下文
# 关键:上下文不能从工具参数里取(用户可控,可伪造)
# 必须从鉴权中间件注入
|
铁律:权限上下文只能从鉴权层注入,绝不能让 LLM 传(LLM 的参数是用户可控的,伪造身份就洞穿了)。
五、第四道:审计与限流#
审计(必做)#
1
2
3
4
5
6
7
8
9
|
{
"ts": "2026-04-15T10:00:00",
"token_owner": "agent-interviewer",
"tool": "resume.search",
"args": {"query": "Go 后端 3 年"},
"result_count": 12,
"latency_ms": 45,
"status": "ok"
}
|
审计的价值:出事故能还原"谁、什么时候、查了什么、返回了什么"——没有审计,安全事件无从查起。
六、Prompt 注入的应对#
工具返回的数据里带指令:
完全防住 Prompt 注入是做不到的,但结构校验 + 隔离可以大幅降低风险面。
七、生产 Checklist#
MCP 安全的核心认知:
- 威胁不是"接口被黑",是"能力被滥用":越权、刷量、注入
- 三层防线:Token 鉴权 → 工具级权限 → 数据级过滤
- 会话隔离:权限上下文从鉴权层注入,绝不让 LLM 传
- 审计 + 限流:出事查得到,滥用扛得住
MCP 是把"能力"交给 LLM 的协议——能力越大,边界越要清楚。 安全设计不是 MCP 的可选项,是企业落地的第一道门槛。
微信公众号「福清而不淡」
后端架构 · AI 工程 · 云原生的一线实践,扫码关注,不错过更新。
本文已同步发布到公众号,欢迎留言交流。