阅读需 8 分钟

在访问敏感服务前固定代理客户端版本

代理客户端版本固定让团队能够测试已知的本地构建版本、验证其身份,并控制它何时可以访问敏感服务。

在访问敏感服务前固定代理客户端版本

本地代理客户端不应仅仅因为名字出现在获准工具列表中,就获得敏感服务的访问权限。真正决定请求内容的是可执行文件、运行时、扩展以及它的启动方式。只要其中任何一项发生变化,你面对的就是不同的安全主体,即使窗口标题和命令名称看起来仍然熟悉。

代理客户端版本固定是一种发布控制措施,不是解决糟糕提示词或权限过大的办法。它带来一个实用特性:你可以测试一个已知构件,记录测试对象,并拒绝让未经审查的替代版本访问敏感服务。听起来很普通,却能避免许多本可避免的故障。

我见过一些团队在保险库和审批对话框上投入了大量精力,却允许桌面更新器在夜间替换发起这些请求的程序。他们依然保留了人工参与,但人工批准的是一段没人评估过的代码所产生的行为。这算不上有意义的边界。

固定可执行文件身份,而不是友好的版本标签

确切的版本号必不可少,但单靠它还不足以准确识别本地客户端。2.4.1 这样的发布标签只能说明发布者打算发布什么。它不能证明你安装了哪些字节、是谁签署了它们、哪个运行时启动了它,或者某个扩展是否在启动后改变了它的行为。

一份可用的批准记录应在多个层面识别构件:

  • 客户端名称和确切的发布字符串。
  • 下载的安装程序或可执行文件的 SHA-256 摘要。
  • 操作系统能够提供时,记录代码签名机构和捆绑标识符。
  • 安装路径、运行时版本和扩展清单。
  • 日期、审查人,以及该记录获准访问的服务或凭据范围。

区分「版本固定」和「构件固定」很重要。版本固定告诉安装器应该寻找哪个发布版本。构件固定则允许你拒绝与测试文件不同的文件。团队经常把这两个概念混为一谈,因为包管理器会用「pin」同时表示二者。后果很糟:他们批准了 1.4.3,却从被入侵的镜像或遭篡改的缓存中收到一个重新构建的 1.4.3,而本地没有任何测试能发现差异。

签名身份可以增加一道检查,但不能替代摘要。合法发布者也可能签署有问题的版本,而仅有摘要又无法说明文件是否来自你预期的发布者。只要客户端能够访问生产系统,两者都应记录。

不要为了文书工作而制造文书工作。这份记录需要在事件发生时回答一个问题:「哪个代码有权发送这个请求?」如果它只写着「编程代理」,就无法回答这个问题。

锁定依赖树不等于审查客户端

锁文件很有帮助,但它解决的问题比许多团队想象的更窄。包锁定文件会为某次安装选择依赖版本,却不会检查原生模块、验证每个安装后操作、阻止运行时从用户目录加载代码,也不能证明启动的可执行文件就是审查人检查过的构件。

对于通过语言生态分发的客户端,这一点尤其重要。一个看似只有一个程序的命令,实际可能由一个小型启动器、一个运行时、一棵包依赖树以及一个或多个下载的插件组成。只固定顶层包,可能会让信任决定中最大的一部分处于未控制状态。

OpenSSF SLSA 规范清楚地区分了来源信息和完整性。来源信息描述构件在哪里、如何构建。完整性检查确认构件没有发生变化。这两种声明都不代表程序适合获得凭据,但它们仍然重要,因为团队无法审查或复现一个不断变化的目标。

先弄清开发者启动代理时究竟运行了什么。在 macOS 上,应向 shell 查询,而不是相信 Dock 图标:

command -v agent-client
file "$(command -v agent-client)"
head -n 1 "$(command -v agent-client)"

当第一个结果是脚本时,head 命令就很重要。第一行如果是 #!/usr/bin/env node,说明 Node 运行时和包依赖树都属于执行路径。如果第一行把任务交给另一个启动器,就需要继续追踪。不要把 shell 别名、符号链接或引导脚本当成客户端来批准。

对于应用程序捆绑包,应检查真正的可执行文件和签名元数据:

APP="/Applications/Agent Client.app"
BIN="$APP/Contents/MacOS/Agent Client"
shasum -a 256 "$BIN"
codesign -dv --verbose=4 "$APP" 2>&1 | grep -E 'Identifier=|TeamIdentifier=|Authority='
spctl --assess --type execute --verbose=4 "$APP"

哈希输出通常形如 digest pathcodesign 输出一般会包含标识符、团队标识符和一条或多条机构信息。将这些输出与批准记录一起保存。spctl 会要求 macOS 按当前安全策略评估应用。它是有用的证据,但不代表这个应用就应该获得部署凭据的访问权限。

只写一句「锁文件已提交」的审查记录,留下了太多未解答的问题。保留锁文件,然后识别真正发起敏感操作的构件。

协议兼容性不能证明客户端可信

客户端可以正确使用代理协议,却仍然不适合访问敏感服务。协议兼容性回答的是两个程序能否交换消息。客户端信任回答的是:特定程序以特定状态启动后,是否可以请求需要凭据的操作。

Model Context Protocol 文档描述了客户端和服务器在初始化期间交换声明的能力。这种能力协商对互操作很有用,但它不是对客户端二进制文件的证明,也不是对已加载扩展的声明,更不保证客户端会保留用户意图。不要把成功握手当成身份检查。

当团队因为某个工具拥有已知的服务器名称,就允许任何支持 MCP 的本地客户端调用敏感工具时,这种混淆就出现了。MCP 服务器看到的是通过协议通道发送的请求,却可能不了解构造请求的程序。恶意客户端或只是未经审查的客户端,都可以使用与测试客户端相同的方法名。

将以下三类记录分开:

  1. 你测试过的协议版本和能力。
  2. 你批准的客户端构件、签名身份、运行时和扩展。
  3. 该客户端可以请求的服务权限。

其中任何一项发生变化,都值得重新审查。协议升级可能改变默认设置或消息处理方式。客户端升级可能改变它调用哪些工具或何时重试。服务权限变化则可能让原本无害的重试变得具有破坏性。

还有一个常被弄错的区别:固定客户端并不会固定代理的指令。用户提示、仓库文件、工具描述、远程内容和模型输出,都可能影响一个已固定的客户端。版本固定只能减少因软件被替换而产生的意外,并不能让任意工具调用变得安全。对于后果难以轻易撤销的操作,应在前面设置人工批准环节。

测试权限路径,而不只是聊天窗口

候选客户端只有在计划开放的完整访问路径中都表现正确,才算通过审查。让它总结仓库或创建临时文件,只能证明用户界面正常,不能测试凭据注入、批准行为、重试、重定向、SSH 主机检查,也不能测试工具返回错误后客户端会做什么。

使用暂存服务或专门创建的范围受限测试凭据。该凭据应能展示目标操作,却不能修改生产数据、轮换共享密钥或访问无关账户。如果无法创建这样的凭据,说明服务的权限粒度对自主客户端来说过粗,需要单独讨论访问设计。

有意识地测试以下情况:

  • 一次普通的获准请求,并收到预期响应。
  • 一次超出凭据范围并被拒绝的请求。
  • 触发重试行为的响应延迟或连接失败。
  • 客户端使用 HTTP 时的重定向或端点变化。
  • 客户端使用 SSH 时的主机密钥变化。

后两项经常能发现令人意外的行为。HTTP 客户端可能会跟随重定向,而重定向可能把请求发往另一台主机。凭据是否跟随,取决于客户端和身份验证实现。你需要观察结果,不能只从发布说明中推断。SSH 客户端必须把主机密钥不匹配视为停止条件,直到有人处理这个变化。代理不应因为任务要求继续,就自行决定陌生的主机密钥可以接受。

记录请求元数据,但不要记录秘密。对于 HTTP,测试端点可以记录方法、主机、路径、状态和选定的非敏感标头。确认网关添加了哪个授权标头,然后确认客户端不会在工具结果、错误消息或本地记录中把该标头值传回来。

对于破坏性端点,让暂存操作留下一个容易识别的标记。只返回 HTTP 200 的测试证明不了多少。你需要证明恰好执行了一次预期操作、重试后没有执行错误操作,并且审计记录能识别正确的会话。

将候选版本与获准客户端隔离

在会话旁查看调用
Sallyport 分别记录代理运行的 Sessions 日志和每次外部调用的 Activity 日志。

候选发布版本应拥有独立的安装、配置、缓存和扩展目录。共享这些目录会让测试构建访问与全新安装不同的状态,也会让回滚变得不可信。我调试过的最令人恼火的问题,往往来自一个「新」客户端悄悄加载旧插件,或复用了已认证的浏览器会话。

在 macOS 上,使用单独的用户账户能为严肃测试提供最干净的边界。单独账户会改变主目录、应用支持目录、缓存、登录项和许多凭据存储位置。对于较快的开发者测试,如果客户端说明了如何选择各个路径,并且你确认它确实遵守这些设置,那么使用单独目录也可以。

不要让两个版本指向同一个可写配置文件。客户端经常在启动时更新配置格式。新版本可能写入旧版本忽略或处理不当的字段。这样会把回滚变成部分迁移,而你恰恰需要让回滚过程平淡可靠。

对扩展的警惕程度应与客户端相同。记录扩展的确切版本、来源位置、可行时记录哈希,并确认客户端是否会自动获取更新。如果客户端会从用户级插件目录这类宽泛目录中发现扩展,候选测试开始时应让该目录保持为空,只添加测试所需的扩展。

干净的测试还会暴露一个不那么光鲜的问题:未记录的依赖。如果候选版本只有在继承获准环境中的环境变量、浏览器 Cookie、shell 函数或全局包缓存后才能工作,就要记录这些输入。每个隐藏依赖都会让日后的行为更难复现。

让推广成为小型、可重复的发布变更

推广应该用另一份经过审查的记录替换当前记录,而不是依靠某个人记得自己点击过哪个下载按钮。每次都写下并执行相同的顺序。这个顺序能让审查人使用共同的术语,也能为值班工程师提供合理的回滚路径。

  1. 从发布者的正常发布渠道下载候选版本,记录来源、确切版本、哈希和签名者。
  2. 将它安装到隔离的测试位置,记录它加载的运行时和扩展。
  3. 使用暂存凭据运行权限路径测试,包括拒绝和失败情况。
  4. 将观察到的请求、提示和日志与获准行为进行比较,调查每一个新增的权限请求。
  5. 将获准候选版本安装到有特权的位置,保留之前的构件,并且只有在安装检查与记录一致后才更改访问权限。

最后的顺序很重要。不要先授予访问权限,再计划稍后检查已安装文件。如果安装检查失败,就让候选版本无法调用敏感服务。拒绝一个发布版本是正常结果,不是流程失败。

使用一份简单的记录,并将它放在运维笔记旁边。YAML 便于人在事件处理中阅读:

client:
  name: agent-client
  version: "2.4.1"
  executable_sha256: "replace-with-verified-digest"
  signer_team_id: "record-the-observed-team-id"
  install_path: "/Applications/Agent Client.app"
  runtime: "native bundle"
review:
  tested_on: "2025-03-08"
  reviewer: "initials"
  extensions: []
access:
  environments: ["staging", "production-read"]
  forbidden_actions: ["secret-rotation", "deployment-write"]
rollback:
  previous_version: "2.4.0"

上面的值是占位符,不是可以复制来当作证据的模板。请根据实际检查结果填写,尤其不要在没有对下载文件进行哈希计算的情况下,直接粘贴发布公告中的摘要。

避免使用「该供应商发布的所有版本都允许」这类宽泛规则。它们很受欢迎,因为可以减少审查工作,也会抹去版本固定提供的精确控制。供应商身份可以作为审查输入,但不能成为未知代码使用生产凭据的长期授权。

自动更新和敏感访问不应共享同一边界

离线验证审计记录
无需保险库密钥,即可对加密审计链运行 sp audit verify。

对于许多桌面应用,自动更新是合理的。当应用可以通过存储的凭据、SSH 密钥或特权服务账户触发外部操作时,风险就变了。在这种情况下,更新器可能在一个工作日到下一个工作日之间替换请求授权的程序。

有三种可行模式。最安全的做法是为有特权的安装禁用自动替换,手动推广发布版本。另一种做法是让开发者使用自动更新但无法访问敏感服务的副本,同时用固定版本的副本处理特权工作。第三种做法是把操作边界放在客户端之外,让每个新进程在执行任何重要操作前都必须获得新的授权。

第三种模式可以限制意外更新造成的损害,但不要夸大它的作用。只有在新的批准卡片能够有意义地识别进程时,新的批准才有用。每天看到通用的客户端名称就点击通过,会训练人们批准任何出现的东西。应显示签名机构、进程路径或其他身份证据,让审查人可以与获准记录进行比较。

不要因为更新后的客户端来自操作系统应用商店,或因为 macOS 认为它已签名,就默默允许它。那些机制可以降低部分供应链风险,但不能说明新行为是否符合你的访问规则。是否授予组织凭据,仍然由你的组织负责。

版本固定还需要定期到期审查。永久固定最终会变成未打补丁的固定版本。根据客户端、它能够访问的服务以及供应商的安全公告设定审查周期。如果行为没有变化,审查不必制造紧张气氛,但必须经过有意识的决定。

按操作授权可以捕捉版本固定无法解决的行为

即使客户端已固定,也可能通过仓库、问题描述、网页或工具结果收到恶意指令。它还可能在你为合法工作授予的权限范围内做出错误选择。人工授权应重点关注具有实质影响的操作,例如写入生产数据、修改基础设施、向新目的地传输数据,或向敏感主机打开 SSH 会话。

如果批准提示要求人们批准技术噪声,就会失效。每个无害读取操作都弹出提示,会训练用户直接点击。请求已经隐藏目标后才出现的提示,也没有多少帮助。在网关发送请求前,显示操作、目的地、方法和凭据身份。选择数量要足够少,确保人确实能评估它们。

一种实用的划分方式是:低风险读取可以通过会话批准,能够改变状态或暴露数据的操作则必须获得明确批准。边界取决于服务。读取源代码仓库可能很普通,读取客户数据库却可能意味着披露数据。不要只按 HTTP 方法分类。

Sallyport 使用固定的决策阶梯:保险库锁定时拒绝所有操作,新代理进程默认需要会话授权,选定的凭据条目可以要求每次使用都批准。这种窄模型是有意设计的。通用策略语言会提供更多旋钮,也会给团队更多机会写出自己并不理解的例外。

让撤销立即生效。当候选客户端行为异常时,应能在开始漫长调查前停止当前访问会话。之后可能还需要撤销服务凭据,但那是一个会破坏无关工作的粗粒度响应。先撤销会话,让正在运行的进程失去访问能力。

审计记录必须把操作连接到获准运行

让凭据远离客户端
Sallyport 会自行注入 HTTP 和 SSH 凭据,因此更新后的代理永远不会拿到这些凭据。

只写着「API 调用成功」的操作日志,不足以支持代理工作。你需要把调用连接到本地进程、批准决定、所用凭据以及当时有效的客户端记录。否则事件审查就会沦为在终端、浏览器历史记录和服务日志之间比对时间戳。

为每个代理进程保留会话记录。记录进程启动时间、用户如何授权、观察到的身份,以及进程结束或被撤销的时间。为单个操作保留独立的活动记录。该记录应标识目的地、操作、结果和会话关联,同时省略秘密材料。

防篡改证据很重要,因为代理可以在很短时间内生成大量工作,而本地日志在出错后很容易被修改。哈希链能让人在验证序列时发现删除或篡改。它不能阻止受入侵的机器执行操作,但能为调查人员发现被改写的历史提供更好的依据。

Sallyport 将 Sessions 和 Activity 日志都投影到同一份加密哈希链审计日志中,sp audit verify 可以在没有保险库密钥的情况下,对密文离线检查哈希链。当审查记录的人不应获得操作所用秘密时,这种设计很有用。

在推广期间测试审计路径。批准一个暂存会话,执行一次获准请求和一次被拒请求,撤销会话,然后确认记录识别出全部四个事件。如果记录无法显示被拒请求或撤销操作,那么你缺少的正是行为出错时最重要的信息。

周边系统保持可变时,版本固定也会失效

即使客户端经过仔细哈希,它仍然运行在一台可能发生变化的机器上。操作系统、运行时、shell 环境、DNS 配置、代理设置、证书存储、本地辅助二进制文件和开发者安装的扩展,都会影响请求如何离开机器。版本固定只是控制链中的一环,不是可以贴在危险设置上的标签。

先检查那些无需改变客户端摘要,就能改变特权操作的部分。检查用于选择端点、代理行为或凭据位置的环境变量。确认客户端调用的是哪个 SSH 二进制文件或辅助程序。记录预期的 known-hosts 位置,并确认测试会拒绝陌生服务器身份。检查配置是否允许将任意本地命令作为工具执行。

不要试图用策略引擎解决所有不确定性。大多数团队需要更少的活动部件,而不是一套凌晨两点没人能解释的大型规则集。目的地短允许列表、范围受限的凭据、敏感调用的明确批准以及已知客户端构件,比一大堆未经测试的条件更有用。

运维习惯其实很简单:客户端发生变化时,暂停访问,直到新构件获得批准。保留旧的获准副本,针对真实权限路径测试替代版本,并记录证据。这种纪律没有自主演示那么令人兴奋,却能防止后台更新变成未经审查的生产变更。

常见问题

我应该把 AI 代理客户端固定到确切版本,还是使用版本范围?

请固定将要请求访问权限的确切构建版本,而不只是固定主版本或次版本。像 ^1.8.0 这样的范围会允许包管理器日后选择其他版本,这就失去了审查的意义。

锁文件足以保护代理客户端吗?

不能。锁文件会固定解析后的依赖版本,但不能证明已安装的可执行文件与审查过的构件一致。保留锁文件,然后验证获准客户端的包哈希、签名或生成它的源代码提交。

如果代理更新后的代码签名不同,我该怎么办?

把代码签名身份的变化视为新的客户端,即使版本字符串没有变化。签名机构说明是谁签署了可执行文件,版本号说明供应商声称它是什么。两项记录都需要保留。

版本固定能让自主代理变得安全吗?

版本固定可以减少普通更新带来的意外,但不能阻止获准构建版本执行恶意指令、滥用获准凭据或加载不安全扩展。仍要保留人工授权和范围受限的凭据。

AI 代理设置中的哪些部分应该固定?

固定打开连接或调用 MCP 服务器的本地二进制文件,同时固定在其进程中运行的托管运行时和扩展。如果启动器会在启动时下载真正的客户端,只固定启动器几乎无法提供控制。

在授予新代理版本生产权限前,应该如何测试?

使用无法影响生产环境的凭据测试完整操作路径。测试被拒绝和获准的调用、批准提示、重定向、格式错误的响应以及 SSH 主机验证。一次成功的提示和响应演示,几乎无法说明权限行为是否正确。

我可以让候选代理版本与获准版本并行运行吗?

为候选构建使用单独的安装目录或单独的 macOS 用户。将配置、缓存、插件和凭据与获准客户端分开,否则测试可能悄悄复用生产状态。

我应该为本地 AI 编程代理禁用自动更新吗?

只有在更新后的客户端未经人工推广就无法访问敏感服务时,自动更新才是可接受的。为有特权的副本禁用自动替换,或者把它放在能够识别获准构建的授权点之后。

代理客户端批准记录中应该包含哪些信息?

记录客户端名称、确切版本、构件摘要、签名机构、安装路径、运行时版本、扩展清单、测试日期、审查人和获准范围。没有摘要和签名者,版本号基本只是一个标签。

如何审计哪个代理版本使用过某个凭据?

一份有用的审计记录会同时记录客户端运行和每次敏感操作,并允许你撤销正在运行的会话。Sallyport 使用不可写入的加密哈希链审计日志保存会话和活动日志,因此可以把访问决定追溯到某次具体的获准运行。

Sallyport

Sallyport 替你的 AI 智能体执行 API 调用和 SSH 命令。密钥留在你 Mac 上的本地密钥库里;每次运行由你批准,每个操作都落入一份密封的审计日志。

© 2026 Sallyport · 依据 Apache-2.0 开源 · Oleg Sotnikov