AI 智能体的 HTTP 身份验证:安全的凭据模式
解释 AI 智能体的 HTTP 身份验证:比较 bearer token、Basic 身份验证和自定义标头,并让凭据远离智能体上下文。

AI 智能体应该能够请求执行 HTTP 操作,却始终不持有让该操作成为可能的凭据。这个原则比请求使用 bearer token、Basic 身份验证还是供应商标头更重要。如果密钥进入智能体上下文,就可能通过提示词、工具追踪、生成的 Shell 命令、代码库文件,或没人打算保留的后续摘要泄露出去。
HTTP 身份验证模式仍然重要,因为每种模式都会影响凭据可能被窃取、重放、意外转发和审计的方式。正确的设计应从 API 要求的方案开始,然后把凭据限制在受信任的执行器中,由它代表智能体发送范围严格定义的请求。
智能体会把普通凭据变成可复制的数据
无人值守的智能体会改变普通 API 凭据的风险,因为它会读写大量不同形式的文本。开发者可能把令牌保存在本地凭据存储中,并将它粘贴到一次请求里。智能体则可能检查环境变量、写入调试输出、组合 curl 命令、创建配置文件,再把工作结果报告给人类。每个操作都会增加一个可重复使用的密钥落地位置。
危险路径一开始往往看起来很普通:
- 任务运行器把
PAYMENTS_TOKEN放进智能体进程的环境变量。 - 智能体运行诊断命令,打印环境变量或写入 Shell 脚本。
- 脚本进入代码库、CI 构件、终端滚屏记录,或另一次智能体工具调用。
- 有人稍后找到这个令牌,并在它过期或操作员撤销之前持续发送有效请求。
这不需要复杂的攻击者。只要令牌变成了某个专门用于复制文本的地方中的文本,就足够了。
不要把针对智能体的访问控制和凭据保密混为一谈。沙箱可以阻止智能体打开目录之外的文件,但如果密钥已经出现在模型上下文、命令参数或工具结果中,沙箱就无能为力。同样,要求用户确认智能体是否可以运行 curl 的审批提示也说明不了多少,如果智能体仍能自由提供主机、路径、请求体和继承来的授权标头。
因此,AI 智能体的 HTTP 身份验证需要两个独立的边界。智能体需要获得提出请求的权限。受信任的组件则需要保管凭据,并拥有发送请求的权限。把两个边界合在一起,就会让智能体拿到可复制的密钥,并让后续控制依赖智能体始终完美地处理它。这种设计假设不合理。
一个简单的测试方法是:问问自己,如果不撤销凭据,能否把完整的智能体对话记录粘贴到工单系统中。如果答案是否定的,说明密钥已经越过了错误的边界。
Bearer token 易于发送,也容易被重放
Bearer token 会向任何出示它的人授予访问权限。因此,除非你接受“对话记录泄露就可能变成 API 访问泄露”这一结果,否则绝不能把它交给智能体。RFC 6750 规定了在 Authorization 请求标头中使用 bearer token 的方式:
GET /v1/projects/alpha/releases HTTP/1.1
Host: api.example.test
Authorization: Bearer eyJhbGciOi...
Accept: application/json
服务器不需要证明发送者是指定的智能体、原始用户或原始机器。它只需检查提供的令牌是否有效并获得授权。这个特性让 HTTP 客户端保持简单,但也意味着任何拿到复制令牌的人都能使用它。
RFC 6750 允许在有限条件下通过表单请求体发送 bearer token,也描述了在旧式场景中通过 URI 查询发送的方式。不要把它放进查询字符串。URL 比大多数团队预想的更容易进入浏览器历史记录、代理日志、分析系统、Referer 标头、支持工单和应用日志。该标准本身也警告说,通过 URI 传输很容易泄露。没有理由让智能体的密钥成为 URL 的一部分。
只有在周边凭据设计能够限制损害时,bearer token 才适合智能体。优先选择具有明确 API 受众、权限范围窄、有效期短,并且为操作执行器设置独立身份的令牌。一个可以管理所有项目、读取所有客户记录且永不过期的 API token,本质上就是生产环境的主凭据,只是名字听起来更友好。
把 bearer token 交给智能体的常见理由是速度:一个环境变量、一个 HTTP 客户端,不需要额外组件。它在演示中很受欢迎,因为确实能用。但一旦智能体需要调试、委托、长时间运行,或访问多个服务,这种做法就会失败。被复制进上下文的令牌更难有选择地撤销,因为你已经不知道它去过哪些地方。
还有一个陷阱:名字看起来权限受限的令牌,实际权限仍可能很广。应阅读供应商文档,了解真实的权限范围模型。有些服务按端点设置权限范围,有些按组织、项目、代码库或账户授予权限。有些 API token 会悄悄继承创建者用户的全部权限。令牌标签不能证明它的限制。
中介可以保管 bearer token,并在验证请求目标后才构造标头。智能体应提交意图和请求数据,例如“使用这个请求体在 alpha 项目中创建一个发布”,而不是提交字面形式的 Authorization 标头。执行器在验证后添加密钥,并在向智能体返回任何记录前将其移除。
Basic 身份验证需要独立的服务身份
通过 TLS 使用受限的服务账户时,Basic 身份验证可以接受,但用人类用户的用户名和密码来授权智能体是很差的做法。RFC 7617 规定的线路格式,是将 user-id:password 进行 Base64 编码后放入 Authorization 标头:
Authorization: Basic YWdlbnQtcmVsZWFzZXI6czNjcjN0LXZhbHVl
任何能读取该值的人都可以将它解码。Base64 只是改变了表示形式,并没有保护该值。TLS 可以保护客户端与服务器之间的连接,却无法保护已经被智能体、本地进程、调试日志或代理复制的凭据。
许多 API 供应商会在 Basic 身份验证中使用 API token 作为密码,并使用固定用户名或忽略用户名。这并不会把该方案变成更弱的 bearer 身份验证,而是带来类似的重放风险,以及一些实际问题。客户端或日志记录器可能记录解码后的用户名、原始标头,或两者都记录。开发者也可能因为协议把第二个字段称为密码,就复用真实账户密码。这正是不能委托给自主进程的凭据。
如果无法避免 Basic 身份验证,就为执行器创建专用账户。只授予请求类型所需的权限。不要使用个人账户、管理员账户,或在无关自动化任务之间共享的凭据。独立的服务身份可以支持撤销和调查,不会锁定某个人,也不会一次性破坏所有任务。
要有意识地处理字符编码。RFC 7617 描述了用户名和密码字符集方面的兼容性问题,并允许服务器声明支持 UTF-8。如果供应商只支持普通 ASCII 值,就让机器凭据保持在该字符集内。不要在智能体提示词中自行设计编码步骤,因为这会增加一个可能转换和记录密钥的不一致位置。
请求执行器应该自行从受保护的字段构造 Basic 标头。智能体可以选择已批准的操作并提供非敏感参数,但不应构造 Base64 值,也绝不能在错误消息中看到解码后的凭据。安全的错误消息可以说所选凭据引用的身份验证失败,但不应回显标头,也不应告诉智能体密码的哪一部分匹配。
自定义标头需要准确遵循供应商语义
自定义身份验证标头能否安全工作,取决于 API 文档规定的验证规则,以及你对标头值的处理方式。常见例子包括 X-API-Key、Api-Key 或供应商专用标头。有些供应商要求静态 API key,有些则要求携带时间戳、随机数、规范化路径和请求体摘要的签名请求。把所有自定义标头当成同一种东西,既会导致身份验证失败,也可能让凭据被意外发送到更广泛的范围。
首先,严格遵循供应商规范。HTTP 标头名称不区分大小写,但标头值和签名输入可能区分大小写。签名方案可能要求特定的规范化顺序、完全一致的请求体字节以及有限的时间戳窗口。如果执行器先解析 JSON,再重新序列化后签名,就可能生成看起来有效但字节序列不同的 JSON。供应商随后会拒绝请求,人们往往因此关闭签名检查,或加入宽泛的重试逻辑。正确的做法是修复字节处理。
其次,要区分用于身份验证的标头和用于标识客户端的标头。User-Agent、请求 ID 和应用标识可以帮助供应商观察流量,但通常不能证明权限。反过来,X-API-Key 标头可能和 Authorization: Bearer 一样容易被重放。不要因为标头名称中没有“authorization”这个词,就低估它的敏感性。
第三,要阻止智能体进行标头注入。如果受保护的执行器还会注入凭据,就不要给智能体一个可以自由填写的出站标头映射。自由填写的映射允许它添加第二个 Authorization 标头、覆盖预期的内容类型、附加未经批准的身份标识标头,或以审查者看不到的方式影响下游代理。
使用包含命名字段和类型约束的请求契约。例如:
{
"credential_ref": "release-service",
"method": "POST",
"url": "https://api.example.test/v1/projects/alpha/releases",
"headers": {
"accept": "application/json"
},
"body": {
"version": "2025.06.0",
"notes": "Fix parser crash on empty input"
}
}
由执行器而不是智能体负责将 credential_ref 映射到供应商的自定义标头或签名流程。它应该拒绝智能体提供 authorization、cookie、供应商凭据标头、host,以及这些名称的重复形式。Content-Length 也应由执行器负责,因为 HTTP 客户端必须根据最终字节数计算它。
向智能体展示响应时也要遵守同样的原则。HTTP 响应可能包含 Set-Cookie、诊断信息或回显的请求细节。只返回任务所需的状态、经过选择的安全响应标头和请求体。如果操作员需要原始标头和追踪信息,就将它们保存在受保护的审计存储中。
选择供应商要求的方案,然后限制影响范围
你很少能决定第三方 API 使用哪种身份验证方案,因为供应商已经做出了选择。但你可以决定凭据的权限范围是宽还是窄、存放在哪里、哪些请求可以使用它,以及智能体行为异常时如何处理。
设计边界时可以参考下面的比较:
| 模式 | 客户端发送的内容 | 被复制后的主要风险 | 合理的智能体处理方式 |
|---|---|---|---|
| Bearer token | Authorization 中的令牌 | 接收者可以直接重放 | 保存在执行器中,并限制权限范围和有效期 |
| Basic 身份验证 | 用户名和密码或令牌的 Base64 编码 | 解码后可以直接重放 | 在执行器中使用专用服务身份 |
| 静态自定义标头 | 供应商定义的密钥标头 | 通常可以直接重放 | 只为已批准的主机和路径注入 |
| 签名自定义标头 | 签名、时间戳和请求数据 | 重用可能失败,但签名材料仍然敏感 | 将签名密钥和规范化逻辑保留在执行器中 |
对签名请求要作出重要限定。时间戳和随机数可以减少 API 边界上的直接重放,但不会让签名密钥适合进入智能体上下文。能够访问密钥的智能体可以签署新的恶意请求。如果签名实现接受智能体提供的任意方法、主机、路径和请求体,它就会忠实地为你本来不想授权的操作签名。
权限范围应与操作匹配,而不是为想象中的未来用途预留。发布智能体可能只需要在一个项目中创建发布的权限,但不需要删除项目、修改账单、读取所有构件或邀请用户。如果供应商无法提供足够受限的凭据,就在供应商 API 前部署一个由你控制的、更窄的服务,或对危险调用保留人工审批。
不要用自然语言写一长串允许列表来弥补权限范围过宽的问题。“只能用这个令牌发布”是建议,不是执行点。应在组装请求的地方限制预期来源、允许的方法、路径模式、标头集合、请求体结构和最大响应大小。这些约束能让凭据离开预期任务后变得不那么有用。
中介机制让密钥远离智能体上下文
经过中介的 HTTP 调用只有在密钥持有者执行请求,而不是返回密钥让智能体执行时,才真正有效。两种设计都可能向智能体提供名为 http_request 的工具,因此很容易混淆。数据流才说明你实际构建的是哪一种设计。
在不安全的设计中,工具会获取令牌并交给智能体,可能是环境变量、占位符替换,或所谓的“临时”凭据。智能体的下一步操作会发送请求。此时令牌已经进入一个专门用于推理、转换和重复文本的系统。
在经过中介的设计中,智能体向执行器发送结构化请求。执行器检查请求是否符合允许的形状,从受保护的存储中取出选定凭据,注入正确的身份验证材料,发送请求,记录操作,并返回受限结果。智能体永远不会获得密钥值、密钥的编码形式,或包含密钥的 Shell 命令。
这个差异也会改变事件响应方式。如果怀疑某次智能体会话出了问题,可以先停止它请求操作的能力,而不必立即轮换所有凭据。如果凭据本身可能已经泄露,仍然要轮换。会话撤销和凭据轮换解决的是不同问题,把它们当成同一个按钮会浪费团队时间。
实际的执行器默认应拒绝以下几类请求:
- 指向未批准来源的绝对 URL,包括相似的仿冒子域名。
- 由用户提供的
Authorization、Cookie、代理或特定凭据标头。 - 可能将经过身份验证的请求带到其他来源的重定向。
- 超出凭据预期用途的方法,尤其是破坏性方法。
- 超出预期大小,或不符合端点预期格式的请求体。
Sallyport 在 macOS 上采用这种保管模式:其加密保险库存放 API 和 SSH 凭据,而 MCP 智能体请求应用执行 HTTP 调用,而不是接收凭据值。
不要把中介机制误认为通用策略引擎。它无法判断“删除过期测试资源”在某个生产账户中是否正确。它可以确保请求处于定义好的技术边界内,并确保凭据留在智能体上下文之外。人工审查、权限受限的账户和特定应用的保护措施,仍然决定该操作本身是否值得批准。
请求边界必须涵盖重定向、DNS 和响应
仅批准 https://api.example.test 仍然过于宽泛,因为带凭据的请求不只有主机名。执行器需要控制智能体能够改变有效目标或请求含义的每个位置。
从精确来源开始,也就是协议、主机名和端口。对于普通互联网 API 凭据,要求使用 HTTPS。RFC 9110 定义了 HTTP 请求目标和权限规则,但应用代码仍需执行自己的目标规则。不要只按后缀批准主机。类似“主机名以 example.test 结尾”的检查可能会接受 notexample.test,宽松的子字符串检查更危险。应将解析后的主机名与精确允许列表进行比较,或使用经过有意设计的子域名规则。
然后限制方法和路径。如果智能体应该创建发布,就只允许它需要的精确 POST 路径范围。不要因为清理操作可能有用就加入 DELETE。不要允许任意版本化路径,除非你已经确认后续 API 版本不会带来不同的行为。路径规范化同样重要。比较前先解析 URL;如果匹配代码无法稳定处理,就拒绝异常编码、点号路径段或重复分隔符。
必须明确处理重定向。不同 HTTP 库的行为不同,库升级也可能改变默认设置。对于带凭据的调用,最安全的默认做法是拒绝重定向,并把目标位置报告给智能体。如果供应商确实需要重定向,只允许指定的目标来源,并在同样的限制下重新构造请求。不要假设客户端会始终一致地移除凭据,从而认为开放重定向没有危害。
DNS 会带来第二个目标检查。受信任的主机名可能解析到不断变化的地址,而内部系统的名称可能指向敏感网络。如果执行器运行在开发者的笔记本电脑上,任意出站 HTTP 都可能成为访问本地管理服务或云元数据端点的路径。在建立连接前限制批准的来源,不要接受智能体控制的代理设置,也不要让智能体选择网络接口或解析器。
最后,要限制并过滤响应。智能体不需要下载数 MB 的响应,只为确认发布创建成功。大型响应会浪费上下文,还可能把不受信任服务中的指令带进智能体的推理过程。可以时,只返回下一步操作所需的字段。在工具契约中将远程文本标记为数据,并且绝不能让响应内容改写执行器的授权规则。
审批应说明调用进程和具体操作
只有在人类获得足够信息来做决定时,审批点击才有价值。“允许智能体访问 API”是伪装成提示的宽泛权限。它会导致审批疲劳,因为用户无法判断是哪个本地进程发起请求、请求使用哪个凭据,或它将发送什么内容。
应以能帮助操作员识别的方式标明调用进程。在 macOS 上,代码签名者通常比可变的进程名称更有用。名为 agent 的进程可能是合法的开发工具,也可能是不相关的、恰好使用同名的二进制文件。进程谱系、可执行文件路径和签名信息能提供更好的证据,但它们都不能替代有边界的操作请求。
会话审批和请求审批解决的是不同的取舍。会话审批可以减少对已知智能体运行的重复打扰,适合凭据和请求边界都很窄的低风险、重复性操作。请求审批适合不可逆或敏感的操作,例如对外发布、修改访问设置,或写入会触发其他系统的数据。
不要让用户每次调用都审查一份密集的原始 HTTP 转储。第三次被打断后,人们就会不看内容直接批准。应显示简明的操作摘要:服务身份、方法、目标、路径、有意义的请求体字段,以及 API 文档说明的副作用。原始请求细节可以保留在审计记录中,供日后调查。
还应区分启动会话的权限和保持会话存活的权限。如果智能体进程退出,替代进程不应仅因为名称相同就继承审批。如果用户撤销会话,执行器必须立即停止接受来自该会话的调用。界面显示“已撤销”,但已经获得授权的客户端仍能继续发送请求,这比没有撤销功能更糟,因为它会制造虚假的安全感。
审计记录必须回答智能体退出后发生了什么
有用的审计轨迹应让操作员回答:谁请求了调用、执行器使用了哪个凭据引用、请求发往哪里、执行器允许了什么,以及远程服务返回了什么。回答这些问题不需要记录原始密钥。事实上,记录密钥会创建第二个伪装成可观测性的密钥存储。
每次调用都应保留会话或进程身份、时间戳、选定的凭据引用、HTTP 方法、批准的来源、路径、相关请求数据的受保护表示、响应状态,以及允许或拒绝该请求的决定。若允许重定向,还要记录重定向后的实际最终目标。失败也要记录。针对异常路径反复尝试被拒绝的请求,往往能暴露出有问题的智能体指令或试图越过边界的行为。
防篡改证据会改变你对记录的信任程度。哈希链日志将每条记录与之前的记录关联起来,因此可以在验证时发现后续修改或删除。它不能证明执行器当初做出了明智的授权选择,也不能让已被攻陷的主机变得可信。但它确实会让悄悄修改历史记录变得困难,而这正是事件审查需要的特性。
审计记录应与智能体的普通工作上下文分开。智能体可以收到类似 201 Created, release id r-4821 的摘要。操作员可能需要包含路径和决策元数据的更完整记录。不能因为存在日志,就把原始授权标头提供给任何一方。
在 Sallyport 中,Sessions 和 Activity 日志都来自加密的哈希链审计日志,而 sp audit verify 可以在离线状态下验证该链,无需解锁保险库。这种设计适合审查,因为验证过程不需要暴露授权调用的凭据。
在授予生产访问权限前测试失败路径
只能在正常路径上成功的凭据边界,还没有资格进入生产环境。建立一个小型测试 API,或使用非生产账户,然后让执行器证明它会拒绝那些可能泄露或滥用凭据的情况。
可以按下面的顺序测试:
- 请求一个已批准的
GET端点,确认智能体能收到预期请求体,但收不到包含凭据的标头。 - 由智能体提供
Authorization标头,确认执行器拒绝请求,而不是悄悄合并或替换标头。 - 将 URL 改为未批准的主机,再改为具有欺骗性的相似主机,确认两者都在发出网络请求前失败。
- 让测试 API 返回跨来源的
302响应,确认执行器停止请求,而不是继续转发身份验证信息。 - 在运行期间撤销智能体会话,确认后续调用失败,同时审计验证仍然成功。
测试完成后,检查进程环境、临时目录、Shell 历史记录、生成的文件、崩溃报告和测试日志。搜索已知的测试凭据字符串。这个练习能发现数量惊人的包装脚本和调试模式泄露,而这些问题通常不会在请求级测试中出现。
还要测试供应商错误。API 可能返回回显无效标头内容的请求体、追踪标识符,或要求改用其他端点的建议。确认结果过滤器不会把类似凭据的材料交还给智能体,也确认重试逻辑不会把一次被拒绝的请求变成大量尝试。只有在 API 文档明确说明适合重试的错误上才重试,并保持方法和目标不变。
第一个生产凭据的权限范围应窄到这样的程度:测试失败只会带来不便,而不会造成灾难。如果团队无法准确说明它授权了哪些请求形状,也无法说明如何撤销正在运行的智能体任务,那么这个凭据对于自主使用来说仍然过于宽泛。
常见问题
Bearer token 适合自主 AI 智能体吗?
Bearer token 之所以容易使用,是因为客户端只需在 Authorization 标头中发送一个值。但这也意味着安全边界完全取决于持有令牌的人:任何拿到可用令牌的人通常都能重放它。只有在令牌权限范围窄、有效期短,并且你能迅速处理泄露后的恢复时,才应将 bearer token 交给智能体。
HTTP Basic 身份验证是加密的吗?
Basic 身份验证发送的是经过 Base64 编码的用户名和密码或访问令牌。Base64 是编码,不是加密,因此必须使用 TLS,而且任何能看到该标头的进程都能还原凭据。对于权限严格受限的服务账户,它可能是可接受的,但不适合使用范围广泛的人类账户凭据。
API 智能体什么时候应该使用自定义身份验证标头?
只有在供应商明确记录了自定义标头的用法时,才应使用它,例如 X-API-Key 或供应商专用的签名标头。标头名称本身不会增加安全性,真正重要的是凭据的权限范围、有效期、存储方式和暴露路径。除非协议另有说明,否则应像对待 bearer token 一样保护自定义标头的值。
什么是经过中介的 HTTP 身份验证?
经过中介的调用允许智能体请求某项操作,但不会把授权凭据交给它。另一个受信任的执行器会取出密钥,构造经过身份验证的请求并发送,然后返回经过筛选的结果。这样可以让密钥远离提示词、工具参数、Shell 历史记录和大多数智能体可读取的日志。
凭据网关能让 AI 智能体操作变得安全吗?
不能。网关可以减少凭据暴露,但无法判断智能体想执行的业务操作是否合理。你仍然需要权限范围窄的凭据、明确的端点边界、在后果较大时进行人工审批,以及对返回数据进行审查。
应该允许 AI 智能体通过 API 网关发送什么?
应授权一个具体的请求形状,而不是整个主机名。限制请求方法、允许的路径范围、目标主机和端口、必需的标头名称、请求体类型以及重定向行为。如果智能体可以自由修改其中任何字段,凭据就可能被用于你未打算允许的地方。
编程智能体的 API 凭据应该存放在哪里?
不要通过环境变量、提示词文件、聊天消息、命令参数或智能体能够读取的请求模板传递 API token。这些位置都很容易被回显、提交到代码库、复制进日志,或通过工具结果暴露。应将密钥存放在受保护的保险库中,由受信任的组件在发送请求时注入。
智能体 API 调用应该记录什么?
在活动日志中隐藏凭据,同时保留足够多的不可变上下文来还原操作。记录智能体进程或会话、时间、请求方法、目标地址、路径、状态,以及在适当情况下对请求进行摘要或受保护的表示。只记录“请求成功”的日志过于单薄,无法支持事件调查。
智能体应该携带凭据跟随 HTTP 重定向吗?
不要在重定向到其他来源后继续转发 Authorization 标头。大多数 HTTP 客户端会在跨来源重定向时移除敏感标头,但你仍应测试实际使用的库或执行器。更安全的默认做法是拒绝携带凭据的重定向,除非目标地址已经得到明确批准。
如果 AI 智能体暴露了 API token,我该怎么办?
轮换凭据,撤销智能体会话,保留相关审计记录,并查明暴露期间发出的所有请求。然后确定密钥是如何泄露的:智能体上下文、工具输出、代码库文件、进程环境,还是过于宽松的请求规则。只更换令牌并不能解决问题,原有的泄露路径仍会暴露新凭据。