凭据代理 — 技术

代理的工作原理。

它能防护什么。不能防护什么。

本页面向安全审查员、渗透测试人员以及评估代理威胁模型的工程师。它描述了代理在协议级别的作用、凭据在内存中的存在位置,以及仍然存在的攻击面。

架构

该代理是一个基于 CONNECT 的 HTTPS MITM 代理。AI 智能体将 HTTPS_PROXY 设置为指向它。当智能体发出 HTTPS 请求时,代理会拦截 TLS 连接,检查请求标头中的凭据引用,针对 Clavitor 保管库解析它们,并将注入了凭据的请求转发到上游 API。

默认情况下,代理监听 127.0.0.1:1983 — 即代理和智能体共享主机的 Sidecar 模式。对于共享部署(一个代理在专用网络上为多个智能体提供服务、作为多个工作负载的容器 Sidecar、专用代理主机),可以通过 CLAVITOR_PROXY_LISTEN 配置监听接口。

illustration: unknown name=proxy-sequence

该代理是一个独立的 Go 二进制文件。无 CGO。所有 Clavitor 协议加密操作均经由编译为 WebAssembly 并在启动时通过 wazero 加载的规范 Rust 实现进行处理。

TLS 处理

代理在首次运行时生成一个自签名的 ECDSA P-256 根 CA,并以 0600 权限持久化在二进制文件所在目录中。对于每个上游主机,按需生成叶证书,由此 CA 签名,并缓存在内存中,采用有上限的驱逐机制(1,000 个主机)。叶证书的有效期为 24 小时,并在第 23 小时无感重新生成,以防止在会话中途过期。

智能体必须信任代理的 CA 证书。使用 clavitor-proxy ca 导出它。

上游连接至少使用 TLS 1.3,并通过 ALPN 协商 HTTP/2 和 HTTP/1.1。使用系统证书池进行上游验证。无证书固定 — 代理信任操作系统信任的任何证书。

Credential lifecycle

凭据从不缓存,从不写入磁盘,且保留时间绝不超过一个 HTTP 请求。

阶段凭据存在位置持续时间
保管库中的静态数据保管库数据库中的 AES-GCM 密文直到删除
传输至代理途中来自保管库 API 的 TLS 加密 JSON 响应一次 HTTP 往返
在代理中解密进程内存(堆上的 Go 字符串)一个 HTTP 请求
注入到上游请求中传输至上游线路上的 TLS 加密字节一个 HTTP 请求

代理在其整个运行期间将智能体的凭据解密密钥(16 字节)保存在内存中。它在启动时从加密的 Sidecar 配置(CLV1 格式)加载,并在正常关闭时清除。该密钥绝不会离开进程。

Sidecar 配置使用 AES-128-GCM 和 HMAC-SHA256 进行加密,并使用从静态种子派生的确定性密钥。这是混淆,而非机密性 — 安全边界是文件权限(0600)和对文件的持有。CLV1 格式在代理、CLI 和浏览器扩展之间共享。

解析模式

模式 1 — 显式占位符

智能体在请求标头中包含 clavitor://Entry/field 引用。代理按名称在保管库中搜索该条目,获取它,解密指定字段,并用真实值替换占位符。

如果搜索返回零个或多个结果,代理将返回带有稳定错误代码的 502。占位符绝不会被移除并原样转发。

模式 2 — URL 匹配

当不存在占位符时,代理会向保管库请求 URL 字段与上游主机匹配的条目。如果恰好存在一个具有已识别字段结构的匹配项,代理将自动注入凭据。

零个匹配 → 直通(无凭据预期)。多个匹配 → 带有消歧指导的 502。未知字段形状 → 502

决策树是确定性的:存在占位符 → 解析或失败。无占位符 → URL 匹配或直通。不存在静默回退路径,即解析失败导致请求在没有凭据的情况下发送到上游。

Agent identity

默认情况下,保管库在每个请求中识别到代理自身的智能体 ID。速率限制、作用域检查和审计条目均归属于该代理。

当多个智能体共享一个代理实例时,占位符可以包含智能体 ID:clavitor://agentid@Entry/field。代理将此智能体 ID 发送到保管库,保管库应用该智能体的作用域和速率限制,并记录其访问日志。智能体 ID 是保管库 UI 中智能体详细信息页面上显示的 32 字符十六进制值。

# Without agent ID — attributed to the proxy
Authorization: Bearer clavitor://OpenAI/key

# With agent ID — attributed to agent 0102030405060708090a0b0c0d0e0f10
Authorization: Bearer clavitor://0102030405060708090a0b0c0d0e0f10@OpenAI/key
部署身份模型隔离
每个智能体一个代理代理 ID = 智能体 ID(默认)完全 — 独立的二进制文件、配置、作用域、速率限制
共享代理,URL 中无智能体 ID所有智能体共享代理的 ID共享作用域和速率限制
共享代理 + URL 中的 agentid@每智能体身份每智能体作用域、速率限制和审计

URL 中的智能体 ID 不是身份验证机制 — 代理的 CVT 令牌对连接进行身份验证。智能体 ID 决定归属:应用谁的作用域、计算谁的速率限制、谁的审计跟踪记录该访问。保管库会以显式失败拒绝未知的智能体 ID。

网络安全

SSRF 防护

默认情况下,代理阻止发往专用网络(RFC 1918)、云实例元数据(169.254.169.254)、环回、链路本地和运营商级 NAT 范围的上游连接。首先解析 DNS;在建立 TCP 连接之前验证所有返回的 IP,从而消除 DNS 重绑定 TOCTOU 窗口。

对于合法访问专用 API 的智能体,使用 CLAVITOR_PROXY_ALLOW_PRIVATE=true 进行覆盖。

目标固定

CONNECT 目标主机在隧道建立时被捕获,并在整个隧道生命周期内使用。隧道内的后续请求无法通过操作 Host 标头重定向到其他主机。不匹配会导致 502

这可以防止智能体建立到 api.openai.com 的隧道,然后向 internal-service.corp 发送请求。

标头处理

根据 RFC 7230 §6.1,逐跳标头从请求和响应中剥离:ConnectionKeep-AliveProxy-AuthenticateProxy-AuthorizationProxy-ConnectionTETrailersTransfer-EncodingUpgrade

从上游响应中剥离 Set-Cookie,以防止上游在智能体的 HTTP 客户端中植入 Cookie。

请求和响应主体以流式传输,无需缓冲。默认情况下,请求主体上限为 64 MB(CLAVITOR_PROXY_MAX_BODY_MB)。响应主体以流式传输,无硬性上限;当 Content-Length 超过 100 MB 时,会发出日志警告。

Field-to-header mapping

在 URL 匹配模式下,代理将保管库字段标签映射到 HTTP 标头:

字段标签注入的标头
keyapikeyapi_keytokensecretbeareraccess_tokenAuthorization: Bearer <value>
x-api-keyapi-keyX-API-Key: <value>
username + password(成对)Authorization: Basic base64(user:pass)
其他任何内容已拒绝 — ERR-PROXY-052

在占位符模式下,智能体控制解析哪个字段以及它的去向。上述映射仅适用于 URL 匹配模式。

Error codes

每次失败都会生成一个稳定的 ERR-PROXY-NNN 代码。这些代码是代理公共接口的一部分 — 智能体和操作员可以基于这些代码进行匹配,以触发警报和进行调试。

范围类别
001–019设置(配置、初始化、CA 生成、WASM)
020–029守护进程生命周期
030–049占位符解析(clavitor:// URI)
050–069URL 匹配注入
070–089上游 / TLS

身份字段不可达

保管库条目支持三个加密级别。保管库加密字段是明文元数据。凭据加密字段使用智能体的密钥解密。身份加密字段使用服务器和代理从未见过的密钥加密。只有保管库所有者通过其硬件密钥才能解密它们。

如果占位符引用了身份加密字段,代理将返回 ERR-PROXY-035。无回退机制,无部分结果。该字段在架构上对代理不可达。

代理无法防护的内容

代理的威胁模型是被攻陷的技能或提示注入,导致经过身份验证的智能体收集凭据。保管库的每智能体速率限制、唯一条目配额和两次违规锁定是主要防御措施。代理增加了一个网络层执行点,在此处按请求解析凭据,且智能体从不持有凭据。

受损的主机

代理与智能体在同一台机器上运行。拥有 root 访问权限的攻击者可以读取进程内存、附加调试器或拦截环回流量。代理是一个凭据注入层,而不是硬件安全边界。

通过 API 响应窃取凭据

如果上游 API 在其响应中回显凭据(例如“whoami”端点),智能体会看到该凭据。代理将凭据注入请求,而不是响应。它不过滤返回的内容。

日志记录

代理为每个接受的 CONNECT 请求记录一行日志,并为失败输出错误行。它绝不记录:

  • 解密的凭据值
  • 完整的请求 URL(查询字符串可能携带机密 — 仅记录方案 + 主机 + 路径)
  • 请求或响应主体
  • 凭据解密密钥或 Sidecar 配置内容

当代理检测到来自上游的 400 响应包含与身份验证相关的关键词(unauthorizedinvalid token 等)时,它会记录一条诊断提示,表明注入的凭据可能已失效。响应将原样转发。

加密

所有 Clavitor 协议加密操作 — AES-GCM 字段解密、HKDF 密钥派生、base62 编码、CVT 令牌生成、CLV1 配置打包/解包 — 均在通过 wazero(一个纯 Go WASM 运行时)加载的单个 WebAssembly 模块(clavis_crypto.wasm)内执行。无 CGO。无 Clavitor 原语的 Go 重新实现。

WASM 模块是从浏览器、CLI 和浏览器扩展使用的同一个 Rust crate(clavis-crypto)编译的。单一事实来源,单一二进制文件,单一审计面。

代理使用 Go 的 crypto/tls 处理 TLS 传输,并使用 crypto/ecdsa 生成 MITM 证书。这些属于传输层事项,而非 Clavitor 协议操作。

Configuration

机密(凭据解密密钥、智能体 ID、设备 ID、保管库 URL)存在于加密的 CLV1 Sidecar 配置中,在 clavitor-proxy init 期间写入一次。操作旋钮存在于环境变量中:

变量默认值用途
CLAVITOR_PROXY_LISTEN127.0.0.1监听接口。对于共享部署设置为 0.0.0.0,或设置为特定的接口 IP。
CLAVITOR_PROXY_PORT1983监听端口
CLAVITOR_PROXY_ALLOW_PRIVATEfalse允许连接到 RFC-1918 / 专用网络
CLAVITOR_PROXY_MAX_BODY_MB64请求主体大小上限
CLAVITOR_PROXY_WRITE_TIMEOUT300响应写入超时(秒)
CLAVITOR_CONFIG(exe 目录)覆盖 Sidecar 配置路径

操作旋钮不是机密。它们不属于加密配置。它们属于部署工具已经管理它们的地方 — 环境。

请您自行审查。

加密是一个单一的可审计 WASM 构件。威胁模型已记录在案。如果您发现我们遗漏的内容,我们希望听取您的反馈。