模型全链路权限管理

核心主题:AI 资产管理中的权限治理

当大模型、知识库、Skill、MCP Server 这些 AI 资产进入企业之后,如何系统性地管理它们的访问权限?


目录


一、整体框架

主要问题:当大模型、知识库、Skill、MCP Server 这些 AI 资产进入企业之后,怎么管理它们的访问权限?

本文从四个层次递进展开:

层次 核心问题 内容概要
第一层:AI 资产管理 管什么? 梳理四类 AI 资产及其各自的权限关注点
第二层:权限管理 谁调谁? 拆解三条权限链路的校验机制与安全设计
第三层:身份分类 谁是调用方? 区分人类身份与非人身份,选择对应协议
第四层:安全认证方式 怎么验? 八种认证方式的原理、优劣及在 AI 场景的组合

四层之间的关系:第一层定义"管什么资产",第二层定义"资产之间的权限链路",第三层定义"链路中的调用方是谁",第四层定义"用什么技术手段验证调用方身份"。四层从上到下逐步细化,共同构成完整的权限治理体系


二、第一层:AI 资产管理

企业里的 AI 资产分四类,每类的权限模型不同:

2.1 大模型

谁有权调用哪个模型?是开源模型还是商业 API?调用是否限量(token 配额)?是否允许把敏感数据发给第三方模型?

2.2 知识库

谁有权检索哪个知识库?知识库里的数据有没有分级(公开/内部/机密)?模型检索时是否做了数据脱敏(把敏感内容替换、遮盖、抹除之后再输出给使用者)?

2.3 Skill

谁有权使用哪个 Skill?Skill 内部调用的工具权限是否做了裁剪(权限继承等问题)?

权限继承:指组件内部调用下游服务时,直接使用组件自身服务账号权限执行,而不是使用发起操作的终端用户权限;容易绕过用户权限控制,产生越权漏洞;安全方案是权限透传,下游重新校验原始用户身份。

2.4 MCP Server

谁有权连接哪个 MCP Server?Server 暴露的工具是否做了白名单?Server 的端点是否需要鉴权?


三、第二层:权限管理(三条链路)

在明确了四类 AI 资产之后,需要进一步定义这些资产之间的权限关系。本文将权限关系梳理为三条链路,每条链路解决一类"谁有权调谁"的问题。

3.1 权限链路总览

三条权限链路如下:

  1. 模型 → 知识库/Skill/MCP 的权限:大模型在运行时需要访问知识库(RAG 检索)、调用 Skill(执行任务)、连接 MCP Server(调用工具)。每一步都需要权限校验——不是模型想调就能调,要有明确的授权策略。

  2. Skill → 工具的权限:Skill 内部编排了多个工具调用,每个工具的调用都需要权限校验。前面讨论过的"权限继承问题"就在这里——Skill 不应该继承 Agent 的全部权限,而应该按需分配。

  3. 用户 → AI 资产的权限:最终用户通过 Agent 访问 AI 资产时,需要校验用户是否有权使用这个模型、检索这个知识库、触发这个 Skill。

下面逐一详细拆解每条链路。

3.2 链路一:模型 → 知识库/Skill/MCP

核心目标:控制模型运行时访问下游资源的权限。

实际场景

用户问了一个问题,模型推理过程中需要:

  1. 查知识库(RAG 检索):用户问"公司Q3的销售数据",模型需要去知识库检索

  2. 调 Skill:模型判断需要"生成数据报告",触发对应 Skill

  3. 调 MCP Server 工具:模型需要"查询订单系统",调用 MCP Server 暴露的工具

这三个动作不是模型自己决定的,是 Host/Agent 在模型输出 tool-use 决策后,代为执行的。所以权限校验的时机是 Host 执行工具调用之前

权限校验的设计核心:逐层传递用户身份,逐层校验

img

三个子链路详解

模型 → 知识库

知识库按敏感等级分级(公开/内部/机密),用户角色对应可访问的等级。RAG 检索时,Host 把用户的权限范围传给知识库服务,知识库只返回用户有权访问的文档片段。不是模型检索到什么就用什么,是知识库根据调用者权限做了过滤后再返回。

测试要点:用低权限用户的 JWT 去触发 RAG 检索,验证返回的数据是否包含高权限文档的内容。如果返回了,就是越权漏洞。

模型 → MCP Server

Host 连接 MCP Server 时需要鉴权(远程模式)。MCP Server 验证调用方身份后,还要校验该调用方是否有权调用特定工具。一个 MCP Server 可能暴露 10 个工具,但某个 Agent 只被授权调用其中 3 个。

实现方式:MCP Server 维护一份工具白名单,按调用方身份过滤 tools/list 返回的工具清单。低权限的 Agent 调 tools/list 时,只能看到它有权调用的工具,其余的根本不暴露。

测试要点:用低权限 Agent 的凭证调 tools/list,检查返回的工具列表是否包含未授权工具。然后直接调 tools/call 尝试调用未授权工具,验证是否被拒绝(不能只靠 tools/list 隐藏,tools/call 层也要做权限校验)。

模型 → Skill

Skill 的加载本身需要权限校验——不是所有用户都能触发所有 Skill。Host 在加载 SKILL.md 之前,先检查当前用户/Agent 是否有权使用该 Skill。

认证方式在这条链路中的体现

  • Agent → MCP Server:用 OAuth2 Client Credentials 或 mTLS,Agent 拿一个 service token 证明"我是授权的 Agent"

  • Agent → 知识库:用 JWT 断言,里面带用户身份透传下去,知识库据此做数据级权限过滤

  • Agent → Skill:Skill 加载是 Host 内部行为,但 Skill 内部调工具时走工具的鉴权流程

3.3 链路二:Skill → 工具

核心目标:Skill 内部编排了多个工具调用,Skill 不应该继承 Agent 的全部工具权限,而应该按需分配。

实际场景

一个"生成报告"的 Skill,内部流程是:

  1. 调 search_web 工具搜索资料

  2. 调 read_file 工具读取模板

  3. 调 write_file 工具写出报告

但 Agent 本身还配了 execute_command(执行系统命令)、send_email(发邮件)等高危工具。如果 Skill 继承了 Agent 的全部权限,攻击者通过 Prompt Injection 劫持 Skill 的执行流程后,就能调 execute_command 执行任意命令。

权限模型设计

Skill 级权限裁剪:每个 Skill 在 SKILL.md 中声明自己需要的工具清单,Host 加载 Skill 时只注入这些工具,其余工具对模型不可见:

# SKILL.md 中的权限声明
tools_required:
  - search_web
  - read_file
  - write_file
# 没有声明 execute_command, send_email → 模型在这个 Skill 执行期间看不到这两个工具

两层校验

  • 第一层是可见性控制——Skill 执行期间,Host 只把该 Skill 声明的工具注入模型上下文。

  • 第二层是调用时校验——即使模型被注入攻击后试图调用未授权工具,Host 在执行 tools/call 之前也要校验"当前 Skill 的权限范围内是否包含这个工具",不包含就拒绝。不能只靠可见性控制,因为模型可能被 Prompt Injection 诱导输出不存在的工具名或构造异常调用。

跨 Skill 调用的权限传递

如果一个 Skill A 内部调用了 Skill B,权限处理:

  • Skill B 的权限范围独立于 Skill A,不能继承 A 的权限

  • Skill B 被加载时,Host 重新按 B 的声明注入工具

  • 如果 Skill B 需要用 Skill A 已有的工具,需要在 B 自己的 tools_required 中声明

安全测试要点

  • 构造 Prompt Injection 攻击,诱导模型在 Skill 执行期间调用未声明的工具,验证是否被拦截

  • 检查 Skill 执行完毕后,工具上下文是否恢复为 Agent 的完整工具集(防止 Skill 的权限范围"泄漏"到后续对话)

  • 测试 Skill 嵌套调用时,子 Skill 是否能越权使用父 Skill 的工具

3.4 链路三:用户 → AI 资产

核心目标:最终用户通过前端界面访问 AI 平台时,能使用哪些 AI 资产。

实际场景

用户登录 AI 平台后,能做这些事:

  • 跟大模型对话(哪个模型?)

  • 上传文件到知识库(哪个知识库?)

  • 使用 Skill 完成任务(哪个 Skill?)

  • 触发 Agent 自动执行任务(Agent 能访问哪些工具?)

权限模型设计

RBAC + ABAC 混合模型:

  • RBAC(基于角色):用户关联角色,角色关联资源权限。比如"普通员工"角色能使用对话模型和公开知识库,"数据分析师"角色能使用代码生成模型和机密数据知识库。

  • ABAC(基于属性):在角色之上加条件判断。比如"普通员工"角色有权使用知识库 A,但条件是"工作时间 + 公司内网 + 数据标签非机密"。这适合更细粒度的权限控制。

权限策略示例

{
  # 基础的身份标识
    "user_id": "zhangsan",
    "role": "analyst",
    # permissions:RBAC 核心 —— 用户可访问的全部 AI 资产白名单
    # 对应文档定义的四类 AI 资产 + 底层工具,**只允许列表内资源访问,默认拒绝其余所有**(最小权限原则)
    "permissions": {
    "models": ["qwen-72b-chat", "qwen-coder"],
    "knowledge_bases": ["public-docs", "internal-finance"],
    "skills": ["generate-report", "data-analysis"],
    "mcp_servers": ["internal-db-query"],
    "tools": ["search_web", "read_file", "query_db"]
  },
  # conditions:ABAC 属性条件 —— 使用资源的附加约束(不满足则权限失效)
  "conditions": {
    "time_window": "09:00-18:00",
    "network": "corporate-vpn",
    "max_daily_tokens": 500000
  }
}

认证流程

img

关键设计原则

  • 权限最小化:默认拒绝所有,只显式开放需要的权限。不是"默认开放,按需关闭"。

  • Fail-Closed:权限校验失败或服务不可用时,拒绝请求而非放行。比如权限服务宕机了,应该拒绝所有请求而不是临时放行。

  • 权限透传:用户的 JWT 一路传递到最底层的工具调用,每一层都验。不能只在入口验一次就信任后续所有调用。

  • 动态权限回收:用户权限变更(离职、调岗)后,JWT 应该短期过期或支持主动吊销。不能用永久有效的 token。

安全测试要点

  • 水平越权:用 A 用户的 JWT 尝试访问 B 用户的 AI 资产(如 A 的知识库、A 的对话历史)

  • 垂直越权:用普通用户 JWT 尝试调用管理员才能使用的模型或 Skill

  • 权限绕过:构造异常 JWT(篡改 role 字段、删除 permissions 字段、使用过期 token),验证是否被拒绝

  • 权限泄漏:用户 A 的 Agent 在执行任务时,是否会访问到用户 A 无权访问的资源(Agent 继承了用户身份,但如果权限透传不完整,可能在某个环节丢失用户身份,变成用 Agent 自己的权限访问)

  • 会话劫持:窃取他人的 JWT 后调用 AI 资产,验证是否有 IP 绑定、设备指纹等二次校验

3.5 三条链路的关系

img

三条链路是串联的:用户身份从链路三进入,一路透传到链路二的工具调用。任何一环断了(身份信息丢失、权限校验缺失),都可能导致越权。

核心设计原则就一条:每一次跨资源调用,都要验证"调用方是谁"和"调用方有权做这件事吗"。这跟做传统身份安全测试的逻辑完全一致,只不过资源从"API 接口"变成了"模型、知识库、Skill、MCP 工具"。


四、第三层:身份分类

在权限链路中,调用方分为两大类:人类身份(真实的人通过前端界面访问)和非人身份(服务、Agent、MCP Server 之间的互访)。不同身份类型适用不同的认证协议。

4.1 人类身份

真实的人通过前端界面访问 AI 资产。可选协议:

  • OAuth2:授权码流程,用户通过浏览器跳转登录,适合 Web 应用

  • OIDC:在 OAuth2 之上加了身份层,能拿到用户的身份信息(姓名、邮箱、角色)

  • JWT:用户登录后签发 JWT 令牌,后续请求携带 JWT 证明身份

  • 平台认证:企业内部 SSO(单点登录),对接公司统一身份平台

4.2 非人身份

服务、Agent、MCP Server 之间的互访。可选协议:

  • JWT:服务间调用时携带 JWT 断言,证明"我是服务 A,我有权调用服务 B"

  • 平台认证:内部服务注册中心颁发的服务身份凭证

  • mTLS:双向 TLS 证书认证,双方互相验证证书,适合服务网格架构

  • SPIFFE:云原生环境下的统一身份框架,为每个工作负载分配可验证的身份


五、第四层:安全认证方式

前文梳理了人类身份与非人身份各自可选的协议,下面逐一详解每种认证方式的实现原理、本质缺陷、安全测试要点,以及在 AI 资产管理中的实际用途。

5.0 认证方式总览

人类身份常用

  • API Key / Static Token:最简单但最不安全。一个固定字符串,谁拿到谁能用,无法区分调用者身份,无法做细粒度权限控制。适合内部低敏感场景,不适合生产环境的高权限操作。

  • Basic Auth(用户名/密码):每次请求携带 Base64 编码的用户名密码。比 API Key 强一点——但只要密码泄露即全盘沦陷,无法做临时授权,无法做细粒度权限。

非人身份常用

  • AK/SK(云签名 / HMAC 签名):云厂商标准做法。Access Key ID 是公开的标识,Secret Access Key 是私密的密钥。每次请求用 SK 对请求内容做 HMAC 签名,服务端用相同 SK 验签。好处是密钥不传输、签名不可伪造、请求内容防篡改。AWS、百度云、阿里云都用这套。

  • OAuth2 Client Credentials:专门为服务间通信设计的 OAuth2 流程。服务 A 用自己的 client_id 和 client_secret 向授权服务器换 access_token,然后拿 token 调服务 B。好处是 token 有过期时间(不像 API Key 永久有效),授权服务器可以做细粒度权限控制。

  • JWT 断言 / Service Assertion:服务自己签发或由信任方签发的 JWT,里面包含服务身份、权限范围、过期时间。接收方验签后信任 JWT 中的声明。好处是去中心化——不需要每次都去授权服务器验证,本地验签即可。

  • mTLS 证书:双向 TLS。不仅客户端验证服务端证书(普通 HTTPS 做的),服务端也验证客户端证书。只有持有合法证书的客户端才能建立连接。适合高安全要求的服务间通信,Kubernetes、Service Mesh 中广泛使用。

  • SPIFFE:CNCF 的云原生身份框架。为每个工作负载(Pod、容器、进程)分配一个 SPIFFE ID(如 spiffe://example.com/ns/default/sa/my-service),通过 SPIRE 服务器签发短期 SVID(SPIFFE Verifiable Identity Document)。SVID 可以是 JWT 或 X.509 证书。核心价值:在动态的云原生环境中,工作负载没有固定 IP,SPIFFE 提供了不依赖网络位置的身份验证。

以下按复杂度从低到高逐一详解。

5.1 API Key / Static Token

实现原理:最简单粗暴。平台给每个调用方分配一个固定字符串,调用方每次请求在 Header 里带上:

Authorization: Bearer sk-xxxxxxxxxxxxxxxx

服务端收到请求后,拿这个 Key 去数据库查"这个 Key 是谁的、有什么权限",查到就放行。

本质缺陷

  • Key 是明文传输的(即使走 HTTPS,服务端日志、网关日志都可能记录)

  • 永不过期(除非手动轮换),泄露后无法自动失效

  • 无法做细粒度权限(一个 Key 通常对应一组固定权限,无法动态调整)

  • 无法区分调用者(谁拿到了 Key 谁就是"主人")

安全测试要点:检查 API Key 是否出现在前端代码、日志、错误信息中;是否支持吊销;是否有使用期限。

5.2 Basic Auth(用户名/密码)

实现原理:用户名和密码用冒号拼接后做 Base64 编码,放在 HTTP Header 中:

import base64
​
credentials = base64.b64encode(b"admin:Admin@123").decode()
​
# credentials = "YWRtaW46QWRtaW5AMTIz"
​
# 请求时
headers = {"Authorization": f"Basic {credentials}"}

服务端解码后拿到用户名密码,查数据库验证。

本质缺陷

  • Base64 不是加密,是编码,任何人都能解码

  • 每次请求都传密码,泄露风险高

  • 密码改了所有调用方都要改

  • 无法做临时授权

在 AI 资产管理中基本不用,除非对接遗留系统。

5.3 OAuth2

原文链接:OAuth 2.0 授权认证详解-CSDN博客

5.3.1 简述 OAuth2.0

简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。

举个实例来说明:

有一个"云冲印"的网站(客户端),可以将用户(资源拥有者)储存在Google(HTTP服务提供商)的照片,冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片。

所以"云冲印"需要得到用户的授权,Google才会同意"云冲印"读取这些照片。传统方法就是,用户将自己的Google用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点:

(1)"云冲印"为了后续服务会保存用户的账户密码,这样非常不安全

(2)"云冲印"直接获取全部权限,用户无法限制"云冲印"获得的授权范围和时间,且只有修改密码才能收回权限。

(3)第三方软件一旦被破解,会导致用户账户密码泄漏,后果严重。

OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,从而可以和"服务商提供商"进行互动。

5.3.2 OAuth 的授权认证流程

认证思路

OAuth 在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)。"客户端"不能直接登录"服务提供商",只能登录授权层,以此将用户与客户端区分开来。"客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。

"客户端"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。

认证流程

img

1)用户访问第三方应用程序(简称:客户端)以后,客户端要求用户给予授权。

2)用户同意给予客户端授权。

3)客户端使用第 2 步获得的授权,向认证服务器申请令牌。

4)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

5)客户端使用令牌,向资源服务器申请获取资源。

6)资源服务器确认令牌无误,同意向客户端开放资源。

上述中的第 2 步是关键,即用户怎样才能给于客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。

5.3.3 四种授权类型

参考:OAuth2.0入门(一)—— 基本概念详解和图文并茂讲解四种授权类型

为了获得访问令牌(Token),客户端需要先从资源所有者(用户)那里获得授权。授权是以授权许可(Grant Type)的形式来表示的。OAuth定义了四种授权类型:

1. 授权码模式(Authorization Code Grant)

OAuth2.0授权码模式--认证流程

当用户访问资源时,比如在网易云音乐中使用第三方登录功能,例如QQ登录,那么这里的资源就是用户的QQ昵称和头像等信息。此时第三方应用(网易云音乐)将发送请求到授权服务器(QQ)去获取授权,此时授权服务器(QQ)将返回一个界面给用户,用户需要登录到QQ,并同意授权网易云音乐获得某些信息(资源)。当用户同意授权后,授权服务器将返回一个授权码(Authorization Code)给第三方应用,此时第三方应用在通过client_id、client_secret(这是需要第三方应用在授权服务器去申请的)和授权码去获得Access Token和Refresh Token,此时授权码将失效。然后就是第三方应用通过Access Token去资源服务器请求资源了,资源服务器校验Access Token成功后将返回资源给第三方应用。

2. 隐式授权(Implicit Grant)

隐式授权又称简化授权模式,它和授权码模式类似,只不过少了获取授权码的步骤,是直接获取令牌token的,且没有Refresh Token,适用于公开的浏览器单页应用。因为令牌直接从授权服务器返回,所以没有安全保证,令牌容易因为被拦截窃听而泄露。

3. 密码模式(Resource Owner Password Credentials Grant)

OAuth2.0密码模式

首先资源所有者(用户)提供自己的用户名和密码给客户端(Client),然后客户端(Client)携带从用户那里获取的凭证去授权服务器请求Token,授权服务器对客户端进行身份认证,并校验资源所有者的凭证,如果都校验通过,则发放Token。

适用范围:只适用于应用是受信任的场景。一个典型的例子是同一个企业内部的不同产品要使用本企业的 Oauth2.0 体系。在这种情况下,由于是同个企业,不需要向用户展示"xxx将获取以下权限"等字样并询问用户的授权意向,而只需进行用户的身份认证即可。这个时候,只需要用户输入凭证并直接传递给鉴权服务器进行授权即可。

4. 客户端授权模式(Client Credentials Grant)

OAuth2.0客户端模式

客户端(Client)通过Client_id和Client_secret去授权服务器请求Token,授权服务器认证Client_id和Client_secret是否正确,若正确则发放Token给客户端(Client)。最后客户端通过AccessToken请求资源。

适用范围:只适用于应用是受信任的场景。

5.4 JWT(JSON Web Token)

参考文章链接:全网最透彻:JWT Token 到底是什么?原理+结构+流程图

官方定义

JWT = JSON Web Token

一种开放标准(RFC 7519),用于在网络应用中以 JSON 对象的形式安全传递信息

核心特点:

  • 轻量级:数据量小,传输快

  • 自包含:Token 本身携带用户信息,服务器不需要存储 Session

  • 无状态:服务端不需要保存任何会话信息

  • 跨域/跨服务:适合微服务、分布式、前后端分离

一句话总结:JWT 就是一个加密的、自带用户信息的"身份令牌",服务端不用存 Session,直接验签即可认证

5.4.1 JWT 的结构

JWT 由三段组成,用 . 分隔:

eyJhbGciOiJIUzI1NiJ9.
eyJ1c2VyX2lkIjoiemhhbmdzYW4iLCJyb2xlIjoiYW5hbHlzdCIsImV4cCI6MTcyMzQ1NjAwMH0.
s8fJH2k...

三段分别对应:Header.Payload.Signature

Header(算法声明)

作用:描述JWT的加密算法,类型

{
  "alg": "HS256",   // 签名算法:HMAC-SHA256
  "typ": "JWT"      // 类型固定为 JWT
}

Payload(负载——存放数据)

作用:存放用户信息(如userId, username, 过期时间)

注意:默认是Base64编码,并非加密,不能存密码进去。

{
  "user_id": "zhangsan",
  "role": "analyst",
  "permissions": {
    "models": ["qwen-72b-chat"],
    "knowledge_bases": ["public-docs", "internal-finance"],
    "tools": ["search_web", "query_db"]
  },
  "iat": 1723452400,   // 签发时间
  "exp": 1723456000,   // 过期时间(1小时后)
  "iss": "ai-platform-auth",  // 签发方
  "sub": "zhangsan"    // 主体
}

Signature(签名)

作用:防止Token被篡改

HMAC-SHA256(
  base64(header) + "." + base64(payload),
  SECRET_KEY
)

只有服务器持有密钥,只要签名正确,说明 Token 未被篡改。

5.4.2 JWT 的认证流程

  1. 用户登录,发送账号密码

  2. 服务端验证成功

  3. 服务端根据用户信息生成 JWT Token

  4. 服务端把 JWT 返回给前端

  5. 前端存储 JWT(localStorage / Cookie)

  6. 前端每次请求在请求头带上 JWT

  7. 服务端验证签名

    • 签名正确 → 合法用户

    • 签名错误 → 伪造/篡改,拒绝

  8. 完成鉴权

5.4.3 HS256 vs RS256

上面用的是 HS256(对称加密)——签发和验签用同一个 SECRET_KEY。问题是:任何知道 SECRET_KEY 的服务都能伪造 token。

生产环境通常用 RS256(非对称加密):

# 签发方用私钥签
token = jwt.encode(payload, PRIVATE_KEY, algorithm="RS256")
# 验证方用公钥验(公钥可以公开分发,拿到公钥也无法伪造 token)
payload = jwt.decode(token, PUBLIC_KEY, algorithms=["RS256"])

在 AI 资产管理中的应用:授权服务器持有私钥签发 JWT,模型网关、知识库服务、MCP Server 各自用公钥验签。不需要每次都去授权服务器验证 token 是否有效,本地验签即可,性能更好。

5.4.4 JWT 断言(Service Assertion)

服务自身自己签发,不经过统一授权服务器,专门用于AI 体系内服务与服务之间的调用认证(Agent ↔ MCP、Agent ↔ 知识库、Skill ↔ 工具)。 核心:Agent 服务用自己的私钥生成一段自证身份的 JWT,调用下游 MCP / 知识库时带上;下游服务提前持有该 Agent 的公钥,本地验签就能确认调用方身份,不需要远程请求授权服务器鉴权,实现服务间点对点互信。

# 载荷:声明本次调用的身份、目标、权限、有效期
{
    "sub": "agent-service-a",          # subject:调用主体,当前是谁发起请求(Agent A)
    "iss": "agent-service-a",          # issuer:签发者,自己给自己发凭证
    "aud": "mcp-server-db",            # audience:受众,这个JWT只能给MCP数据库服务使用
    "scope": "tools:call",             # 权限范围:仅允许执行工具调用操作
    "exp": int(time.time()) + 300      # 过期时间:仅5分钟有效,短期凭证降低泄露风险
}
# 用Agent自身私钥签名
jwt.encode(..., AGENT_PRIVATE_KEY, algorithm="RS256")

MCP Server 收到后用 Agent 的公钥验签,确认"这确实是 Agent A 签发的,它有权调我的工具"。

关键区别:不经过授权服务器,服务间直接互信。前提是双方预先交换了公钥。

  1. RS256非对称加密是关键

    • Agent持有私钥:只有它能生成合法断言JWT;

    • MCP服务持有Agent的公钥:仅能验证签名,无法伪造新的JWT; 解决了对称HS256密钥共享带来的伪造风险。

  2. 请求携带方式:放在HTTP标准Authorization: Bearer请求头,和用户JWT传输格式统一,网关、服务统一解析逻辑。

完整调用流程(Agent A 调用数据库MCP服务)

  1. Agent需要查询数据库工具,本地生成一段JWT断言;

  2. 在请求头附上该断言,发起POST请求到MCP-DB服务;

  3. MCP服务拿到JWT后,使用预先同步的agent-service-a公钥本地验签;

  4. 验签通过后校验载荷约束:

    • 校验aud:确认这个Token是发给自己的,不能拿来调用其他服务;

    • 校验exp:判断凭证未过期;

    • 校验scope:确认仅允许工具调用,无越权操作;

  5. 全部校验通过,才允许Agent调用内部数据库查询工具;任意一项不满足直接返回403拒绝。

和普通授权服务器JWT的核心区别

维度 统一授权服务器JWT(用户侧) JWT服务断言(Service Assertion)
签发方 独立授权中心服务 调用方服务自身(Agent自己签发)
依赖 必须依赖授权服务器,鉴权可联动中心黑名单、动态权限回收 去中心化,本地公钥验签,不依赖第三方服务
使用对象 人类终端用户 非人服务、Agent、Skill、MCP等内部组件
信任前提 所有服务信任授权中心 上下游服务提前交换公钥,点对点互信
权限回收 授权中心可主动吊销token、实时修改权限 无法实时回收,只能等待exp过期,固有短板

在AI全链路权限框架里的业务价值

结合文档三层权限链路,它主要解决链路一、链路二的服务间鉴权问题:

  1. 链路一:模型→MCP/知识库 Agent调用MCP Server时,用JWT断言证明自身服务身份,MCP基于断言过滤可调用工具白名单;同时断言内部可嵌套透传用户JWT,实现「服务身份+终端用户身份」双重校验。

  2. 链路二:Skill→底层工具 Skill服务自签断言,限定scope仅包含自身SKILL.md声明的工具,防止Prompt Injection越权调用高危工具。

  3. 性能优势 微服务集群大规模调用时,不用每次鉴权都远程请求授权服务器,本地验签,大幅降低授权中心压力。

安全测试要点

  1. alg算法篡改漏洞 攻击者截获断言后,把签名算法RS256改成none(无签名)或HS256,跳过验签伪造载荷。 校验标准:服务端必须强制校验alg字段,只允许预定义的RS256,拒绝none、HS256等非法算法。

  2. exp过期校验缺失 若服务不判断过期时间,泄露的过期断言可无限重放调用;标准:拒绝已超过exp时间的所有JWT断言。

  3. aud受众校验缺失 攻击者把发给MCP-DB的断言,拿去调用MCP-运维服务;若不校验aud,会发生跨服务越权。标准:仅放行aud与当前服务名称匹配的token。

  4. 权限无法动态回收(固有缺陷) 断言是服务本地签发,授权中心无管控能力。如果Agent权限被回收、Agent被下线,已签发未过期的断言仍能正常使用,只能等5分钟过期。 优化方案:缩短exp有效期(文档示例仅5分钟)、搭配mTLS/SPIFFE做双重身份兜底。

  5. 私钥泄露风险 Agent私钥是信任根,一旦泄露,攻击者可伪造任意JWT断言,完全冒充Agent调用所有下游资源。 防护:私钥不能明文存代码/配置文件,使用密钥管理服务KMS、容器密钥挂载。

适用场景与不适用场景

适合使用JWT断言

企业内部AI集群服务间高频调用:Agent ↔ MCP、Agent ↔ 知识库、Skill ↔ 工具,追求低延迟、去中心化鉴权。

不适合使用

  1. 面向外部第三方调用(无法提前交换公钥,改用OAuth2 Client Credentials);

  2. 需要实时、立即回收权限的场景(优先使用授权服务器统一签发的JWT,支持黑名单吊销);

  3. 公网开放接口(优先mTLS、AK/SK签名,安全性更强)。

5.5 AK/SK(云签名 / HMAC 签名)

参考文章链接:公有云API的认证方式:AK/SK 简介_ak,sk-CSDN博客

AK/SK(aksk)鉴权原理简介_ak sk原理-CSDN博客

ak/sk 是一种身份认证方式,常用于系统间接口调用时的身份验证,其中 ak 为 Access Key ID,sk 为 Secret Access Key。客户端和服务端两者会协商保存一份相同的 sk,其中 sk 必须保密。

  • AK:Access Key Id,用于标示用户

  • SK:Secret Access Key,是用户用于加密认证字符串和用来验证认证字符串的密钥,其中 SK 必须保密

通过使用 Access Key Id / Secret Access Key 加密的方法来验证某个请求的发送者身份。

客户端在调用服务端接口的时候,会带上 ak 以及 signature(使用 sk 对内容进行加密后得出的签名)进行请求,在服务端接收到这个请求的时候,首先会根据 ak 去数据库里面去找到对应的 sk,然后使用 sk 对请求内容进行加密得到一个签名,然后对比客户端传过来的签名和服务端计算的出来的签名是否一致,如果一致则代表身份认证通过,反之则不通过。

使用机制

云主机接收到用户的请求后,系统将使用 AK 对应的相同的 SK 和同样的认证机制生成认证字符串,并与用户请求中包含的认证字符串进行比对。如果认证字符串相同,系统认为用户拥有指定的操作权限,并执行相关操作;如果认证字符串不同,系统将忽略该操作并返回错误码。

流程

  1. 判断用户请求中是否包含 Authorization 认证字符串。如果包含认证字符串,则执行下一步操作。

  2. 基于 HTTP 请求信息,使用相同的算法,生成 Signature 字符串。

  3. 使用服务器生成的 Signature 字符串与用户提供的字符串进行比对,如果内容不一致,则认为认证失败,拒绝该请求;如果内容一致,则表示认证成功,系统将按照用户的请求内容进行操作。

原理

客户端:

  1. 构建 http 请求(包含 access key)

  2. 使用请求内容和 secret access key 计算的签名(signature)

  3. 发送请求到服务端

服务端:

  1. 根据发送的 access key 查找数据库得到对应的 secret-key

  2. 使用同样的算法将请求内容和 secret-key 一起计算签名(signature),与客户端步骤 2 相同

  3. 对比用户发送的签名和服务端计算的签名,两者相同则认证通过,否则失败

实现原理

不传输密钥本身,而是用密钥对请求内容做签名,服务端用相同密钥验签:

import hmac
import hashlib
import base64
​
def sign_request(method, url, headers, body, sk):
    # 1. 构造待签名字符串(Canonical Request)
    canonical_string = f"{method}\n{url}\n{sorted_headers_string}\n{body_hash}"
    
    # 2. 用 SK 做 HMAC-SHA256 签名
    signature = hmac.new(
        sk.encode("utf-8"),
        canonical_string.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()
    
    # 3. 请求中带 AK 和签名
    headers["X-Auth-Key"] = ak
    headers["X-Auth-Signature"] = signature
    headers["X-Auth-Timestamp"] = str(int(time.time()))
    
    return headers

服务端验证:

def verify_signature(request, sk_store):
    ak = request.headers["X-Auth-Key"]
    sk = sk_store.get(ak)  # 根据 AK 查到对应的 SK
    
    # 用相同算法重新计算签名
    expected_signature = compute_signature(request, sk)
    
    # 对比签名(用恒定时间比较防时序攻击)
    if not hmac.compare_digest(expected_signature, request.headers["X-Auth-Signature"]):
        raise Exception("Invalid signature")
    
    # 验证时间戳防重放
    timestamp = int(request.headers["X-Auth-Timestamp"])
    if abs(time.time() - timestamp) > 300:  # 5分钟窗口
        raise Exception("Request expired")

关键安全要素

  • 签名覆盖完整请求:方法 + URL + Headers + Body 都要参与签名。常见漏洞是签名未包含 Body,攻击者拿到签名请求后篡改 Body 内容。

  • 时间戳防重放:请求中带时间戳,服务端拒绝超过窗口期(如 5 分钟)的请求。否则攻击者截获请求后可以无限重放。

  • nonce 防重放:更严格的做法是每次请求带一个随机 nonce,服务端记录已用过的 nonce(缓存 5 分钟),拒绝重复的 nonce。

  • 恒定时间比较:签名对比必须用 hmac.compare_digest 而非 ==。用 == 时,攻击者可以通过测量响应时间逐字节猜解签名(时序攻击)。

在 AI 资产管理中的用途:Agent 调用大模型 API 时用 AK/SK 签名。比 API Key 安全——即使请求被截获,攻击者没有 SK 也无法伪造新请求。

5.6 mTLS(双向 TLS)

参考文章链接:mTLS到底是个啥?服务间双向认证从原理到实战,一篇搞定-腾讯云开发者社区

5.6.1 TLS 基础

在讲 mTLS 之前,我们得先把 TLS 搞明白。日常我们访问 https 网站,浏览器地址栏那个小锁,背后就是 TLS 在工作。

TLS 的核心逻辑其实很简单——单向认证。什么意思呢?就是客户端去验证服务端的身份,但服务端不验证客户端。流程大概是这样:

  1. 客户端发起连接请求,告诉服务端我支持哪些 TLS 版本

  2. 服务端把自己的证书(server.crt)发过来

  3. 客户端验证这个证书是不是可信 CA 签发的,有没有过期,域名对不对

  4. 验证通过后,客户端生成一个随机数作为预主密钥,用服务端公钥加密发过去

  5. 服务端用私钥解密拿到这个随机数

  6. 双方基于这个随机数协商出会话密钥,后续通信就用这个对称密钥加密

img

5.6.2 mTLS 概述

参考文章链接:https://juejin.cn/post/7551782160920199168

mTLS(Mutual Transport Layer Security,双向传输层安全)是一种基于 TLS 协议的增强型身份认证与加密技术,核心区别于传统单向 TLS(仅客户端验证服务器身份),实现了客户端与服务器的双向身份核验,同时保障数据传输的机密性与完整性。它是零信任架构("永不信任,始终验证")中验证服务或终端身份的核心技术之一。

传统单向 TLS 仅解决"客户端确认服务器身份"的问题(如浏览器访问 HTTPS 网站时验证服务器证书),而 mTLS 在此基础上增加了"服务器确认客户端身份"的环节,二者的认证逻辑对比如下:

5.6.3 握手流程

mTLS 基于 TLS 1.2/1.3 协议扩展实现,其核心差异体现在握手阶段的双向证书验证环节。以下以 TLS 1.2 为例,拆解完整握手流程(共 11 步,关键差异步骤已标注):

  1. 客户端发起请求(Client Hello):客户端向服务器发送协议版本、支持的加密套件列表、随机数(Client Random)等信息,表明希望建立 TLS 连接。

  2. 服务器响应(Server Hello):服务器确认协议版本和加密套件,返回随机数(Server Random)、服务器证书(含服务器公钥),并发送"证书请求"(mTLS 关键步骤 1:单向 TLS 无此步骤)。

  3. 客户端验证服务器身份

    • 客户端提取服务器证书,验证证书的有效性:检查证书是否由可信 CA(证书颁发机构)签发、证书是否在有效期内、证书绑定的域名是否与服务器域名一致、证书是否被吊销。

    • 若验证失败,客户端终止连接;若成功,客户端保存服务器公钥。

  4. 客户端提供身份凭证(mTLS 关键步骤 2)

    • 客户端向服务器发送自己的证书(含客户端公钥),以及"证书验证消息"——用客户端私钥对"客户端随机数 + 服务器随机数 + 会话密钥预主密钥"的组合进行签名。

  5. 服务器验证客户端身份

    • 服务器提取客户端证书,重复类似的有效性验证(CA 信任链、有效期、身份绑定等)。

    • 服务器用客户端公钥解密"证书验证消息",核对其中的随机数与握手初期的随机数是否一致,确认客户端确实持有证书对应的私钥(身份真实)。

    • 若验证失败,服务器终止连接;若成功,进入密钥协商阶段。

  6. 密钥协商:客户端与服务器基于各自持有的随机数和预主密钥,通过约定的加密算法生成会话密钥(对称加密密钥,用于后续数据传输)。

  7. 客户端发送"完成消息":客户端用会话密钥加密"握手结束"标识,发送给服务器。

  8. 服务器发送"完成消息":服务器用会话密钥加密"握手结束"标识,发送给客户端。

  9. 握手完成:双方确认会话密钥可用,后续所有通信数据均通过会话密钥进行对称加密(效率高于非对称加密)。

5.6.4 mTLS 依赖的核心技术组件

mTLS 的实现依赖公钥基础设施(PKI)提供身份信任基础,核心组件及作用如下:

1. 数字证书(Digital Certificate)

  • 定义:由可信 CA 签发的电子凭证,包含持有者身份信息(如服务名、设备 ID)、持有者公钥、CA 签名、有效期等关键信息。

  • 作用:mTLS 中,客户端和服务器通过证书向对方证明"我是我声称的身份",同时提供用于加密和签名的公钥。

2. 证书颁发机构(CA,Certificate Authority)

  • 定义:负责签发、管理和吊销数字证书的可信第三方机构(如公网 CA 赛门铁克、企业内部私有 CA)。

  • 作用:作为"信任锚点",CA 用自己的私钥对证书进行签名,客户端/服务器通过验证 CA 签名确认证书的合法性(前提是信任该 CA 的根证书)。

3. 公钥与私钥(非对称加密算法)

  • 公钥:公开可见,用于加密数据、验证数字签名(如服务器用客户端公钥验证客户端签名)。

  • 私钥:持有者私密保存,用于解密数据、生成数字签名(如客户端用私钥对验证消息签名)。

  • 核心逻辑:"公钥加密的数据仅对应私钥可解密,私钥签名的数据仅对应公钥可验证",确保身份真实性和数据机密性。

4. 证书吊销列表(CRL,Certificate Revocation List)

  • 定义:CA 维护的已签发但因私钥泄露、身份变更等原因失效的证书列表。

  • 作用:解决"证书未过期但已不可信"的问题,客户端/服务器在验证证书时需查询 CRL 或通过 OCSP(在线证书状态协议)确认证书状态。

5.6.5 mTLS 的典型应用场景

mTLS 因强身份认证特性,广泛用于需要严格访问控制的场景,以下为核心场景示例:

1. 服务网格(Service Mesh)

  • 代表技术:Istio、Linkerd。

  • 应用方式:服务网格通过 sidecar 代理(如 Istio 的 Envoy)为服务自动注入 mTLS 能力,无需修改业务代码。例如 Istio 中通过 PeerAuthentication 配置 STRICT 模式,强制服务间通信必须通过 mTLS 认证,防止未授权服务接入网格。

2. API 安全与微服务通信

  • 场景:企业内部微服务集群(如订单服务调用支付服务)、第三方 API 接口(如银行开放平台对接商户系统)。

  • 价值:避免 API 密钥泄露导致的非法调用,通过证书身份唯一标识调用方,实现"基于身份的访问控制(RBAC)"。

3. IoT(物联网)设备通信

  • 场景:工业传感器、智能家居设备与云端平台的通信。

  • 价值:物联网设备数量庞大且易被物理劫持,mTLS 可确保云端仅接收可信设备的数据,同时设备仅连接合法云端,防止数据篡改或设备被伪造。

4. 企业内网安全

  • 场景:员工终端访问企业内网服务(如 OA 系统、数据库)、跨数据中心的服务通信。

  • 价值:替代传统 VPN 的"基于网络边界的信任",实现"基于身份的零信任访问",即使终端处于内网,也需通过 mTLS 验证身份方可访问资源。

安全测试要点

  • 是否真的验证了客户端证书(有些配置错误的服务端虽然要求客户端证书但不验证其合法性)

  • 证书是否过期(过期的证书如果还能用,说明验签逻辑有缺陷)

  • 是否校验证书的 CN/SAN 字段(证书绑定的身份与服务实际身份是否匹配)

  • 私钥是否安全存储(私钥泄露 = 身份被冒充)

  • 是否有证书吊销检查(CRL/OCSP,被吊销的证书是否还能用)

5.7 SPIFFE

详解文章链接:零信任安全之——SPIFFE简介 - 知乎

5.7.1 解决什么问题

在 K8s/云原生环境中,工作负载(Pod/容器)是动态的——IP 随时变、实例随时扩缩容。传统的 IP 白名单、mTLS 证书绑定 IP 的方式都不可行。需要一种不依赖网络位置的身份验证机制。

SPIFFE(Secure Production Identity Framework for Everyone)为每个工作负载分配一个统一格式的身份标识:SPIFFE ID。

5.7.2 核心组件
  • SPIRE Server:集群中的信任根。负责签发 SVID(身份凭证),维护已注册工作负载的身份映射。

  • SPIRE Agent:每个节点上运行一个。负责向 Server 证明本节点的工作负载身份,获取 SVID 后下发给工作负载。

  • SVID(SPIFFE Verifiable Identity Document):工作负载持有的身份凭证,可以是 X.509 证书或 JWT。里面包含 SPIFFE ID。

5.7.3 工作流程
1. 工作负载启动 → 向本节点的 SPIRE Agent 请求 SVID
2. Agent 验证工作负载身份(通过 selector:K8s ServiceAccount、Namespace、镜像哈希等)
3. Agent 向 SPIRE Server 请求签发 SVID
4. Server 签发 SVID(X.509 证书或 JWT),包含 SPIFFE ID
5. 工作负载拿到 SVID,后续通信中使用 SVID 证明身份
5.7.4 SPIFFE ID 格式
spiffe://company.com/ns/production/sa/agent-service-a
         ↑ 信任域    ↑ namespace  ↑ service account

这个 ID 不依赖 IP,无论 Pod 调度到哪个节点、IP 怎么变,身份不变。

5.7.5 两个 Agent 互访的流程
Agent A 要调 Agent B:
​
1. Agent A 用自己的 SVID(X.509 证书)发起 mTLS 连接
2. Agent B 验证 Agent A 的 SVID(通过信任根 CA 验证证书真伪)
3. Agent B 提取 Agent A 的 SPIFFE ID:spiffe://company.com/ns/production/sa/agent-service-a
4. Agent B 查权限策略:agent-service-a 是否有权调我?
5. 有权 → 建立 mTLS 连接,通信

本质:mTLS + 动态身份 + 统一信任框架。底层还是 mTLS,但证书不是静态管理的,而是 SPIRE 自动签发、自动轮换、随工作负载生命周期管理。

5.7.6 在 AI 资产管理中的用途
  • K8s 集群中部署的 Agent Pod 之间互访

  • Agent Pod 调 MCP Server Pod(同集群内)

  • 不需要人工管理证书,SPIRE 自动完成签发和轮换

安全测试要点

  • SPIRE 的 selector 是否严格(如果用 namespace 做 selector,任何同 namespace 的 Pod 都能拿到该身份——应该叠加 ServiceAccount + 镜像哈希等多重 selector)

  • SVID 是否定期轮换(默认 1 小时过期,过期前自动续签)

  • 信任域是否隔离(不同集群/环境是否用不同的信任域)

  • 工作负载下线后 SVID 是否自动失效

5.8 各认证方式在 AI 资产管理中的实际组合

生产环境不会只用一种,而是分场景组合:

用户 → AI 平台前端
  → OAuth2 授权码流程登录,拿到 JWT(带用户身份和权限)
  → 后续请求带 JWT
​
AI 平台后端 → 大模型 API
  → AK/SK 签名(调外部商业模型)
  → 或 mTLS(调内部部署的模型服务)
​
Agent → MCP Server(同集群)
  → SPIFFE(K8s 环境下自动身份)
​
Agent → MCP Server(跨集群/跨网络)
  → OAuth2 Client Credentials 换 token
  → 或 mTLS(高安全场景)
​
Agent → 知识库
  → JWT 断言(带用户身份透传,知识库按用户权限过滤数据)
​
Skill → 工具
  → JWT 断言(带 Skill 声明的权限范围)

核心原则:人类用 OAuth2/JWT,服务间用 mTLS/SPIFFE,跨网络用 AK/SK 或 Client Credentials,身份信息全链路透传,每一层都验。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐