阅读需 8 分钟

用防篡改审计轨迹证明 AI 智能体执行过的操作

AI 智能体的防篡改审计轨迹不能只有日志:了解哈希链、加密、检查点和验证如何证明实际发生的操作。

用防篡改审计轨迹证明 AI 智能体执行过的操作

AI 智能体不需要更好的聊天记录。它们需要在操作离开机器的那一刻生成证据。

这个区别决定了你能否回答这样的事件问题:「这个智能体是否向生产环境推送过内容?由哪个进程执行?谁批准的?远程系统返回了什么?」对话摘要无法承担这个任务。只要清楚它能证明什么、不能证明什么,防篡改日志就可以做到。

我见过一些团队因为终端输出容易保存,就把它当成审计记录。这种做法本末倒置。终端输出在调试时很有用,但作为证据很薄弱,因为写入它的进程可能在产生副作用之前就失败了,可能隐藏了重要参数,也可能后来被完全替换。

这里真正可靠的答案往往很朴素。

操作网关应在执行 HTTP 调用或 SSH 命令时创建记录,把记录封存到有序日志中,并让后续修改变得可见。这样,调查人员拿到的是一个不依赖智能体记忆、提示词或是否愿意承认的证据对象。

对话记录和审计轨迹回答的是不同问题

对话记录说明智能体声称自己尝试做了什么,审计轨迹说明操作边界实际接受并返回了什么。把这两种记录混为一谈,会在自主操作变得危险的地方留下缺口。

假设智能体说,它在打开 SSH 会话后运行了 terraform apply。这段文字无法证明 SSH 连接成功,也无法证明命令到达了目标主机,更无法证明主机接受了命令。它可能只是执行前打印出的计划命令,也可能在第一行就失败了,还可能在事后被包装器修改过。

一条有用的操作记录会把来自不同层面的事实绑定在一起:

  • 发起操作请求的智能体运行任务
  • 接收授权的本地进程身份
  • 通道和目标地址,例如 SSH 主机或 HTTP 来源
  • 规范化的操作摘要和结果状态
  • 日志位置以及前一条记录的哈希值

记录不必变成监控数据倾倒。事实上,把每个请求正文和完整响应正文写入永久日志通常很冒险。部署 API 可能返回访问令牌。SSH 命令可能在环境变量赋值中包含临时密钥。只捕获重建安全决策所需的事实,并严格限制敏感载荷的保留范围。

NIST SP 800-92 将日志管理视为涵盖生成、存储、分析和处置的流程,而不是应用程序倾倒文本的文件夹。这份较早的指导原则同样适用于智能体:日志必须在执行器处生成,存储必须能撑过事件响应,分析也不能依赖被调查行为方的可信度。

操作边界会让事实范围变窄。这是好事。

如果智能体从未拿到凭据,而是请求本地网关完成调用,网关就能记录它实际发送的请求。智能体仍然可能被入侵,但它无法在自己的上下文中悄悄改写网关已经完成的操作历史。

能检测篡改不等于不可变

能检测篡改,意味着验证者可以发现某些变化;不可变,意味着任何人都无法修改或删除数据。这是两种不同的承诺。供应商经常把它们混在一起,因为「不可变」听起来更容易购买。

哈希链让每条记录都依赖于前一条记录。一个简化的记录可能如下所示:

record_1042 = {
  sequence: 1042,
  run_id: "run_7f3c",
  time: "2026-03-18T14:22:09Z",
  action: "ssh.exec",
  destination: "deploy@release-host",
  result: "exit 0",
  previous_hash: "a4c1...",
  hash: "8d72..."
}

实现会以确定性的方式序列化这些字段,根据序列化结果计算哈希,再把前一条记录的哈希放入下一条记录。把 exit 0 改成 exit 1,修改主机,或调换两条记录的顺序,验证都会从那里开始失败。

NIST 的安全哈希标准规定了经批准的哈希算法,它们会生成固定长度的消息摘要。摘要不是加密,也不是签名。它是一种紧凑的绑定材料,让后续记录依赖于之前完全相同的字节。

它能发现编辑,但不能发现所有形式的不诚实。

如果攻击者可以重写日志并重新计算后续所有哈希,就能生成一条仍然可以通过验证的链。如果攻击者删除最后 40 条记录,就能留下一个有效的早期前缀。如果攻击者维护两条独立的链,就能向不同审核人员展示不同历史。哈希链可以告诉你,当前呈现的序列在内部保持一致。但它本身无法证明序列完整,也无法证明它在全局上唯一。

所以,当有人把本地哈希链称为「不可否认性」时,我会提出异议。它不是。不可否认性需要身份绑定,还需要一套即使被指控方不再可信也能继续验证的机制。本地哈希链依然值得使用,但应该准确描述它:它能有效防止随意编辑和存储损坏。

哈希链需要一个写入者无法控制的外部锚点

如果有人保存了日志写入者无法悄悄替换的检查点,哈希链就会更难被重写。没有外部引用,控制写入者的攻击者也控制着你的故事开头。

为日志设置锚点有多种方式,各自的成本和运维适配性不同。

  • 将签名检查点导出到权限范围严格受限的独立账户。
  • 将定期生成的日志根发送到智能体主机无法管理的安全事件存储中。
  • 将加密日志分段复制到离线或仅追加存储中。
  • 让独立监控器保存观测到的日志根,并报告不一致之处。

不要以为目标位置越多,证据就越可靠。由同一管理员控制的云存储桶,即使有五份副本,也可能同时失效。权限分离比复制数量更重要。

Certificate Transparency 提供了一个很有用的思维模型。RFC 9162 使用 Merkle 树支持仅追加日志、包含证明,以及已发布树头之间的一致性证明。该 RFC 也直截了当地指出了难点:不诚实的日志可能会尝试向不同客户端展示不一致的视图。

简单的哈希链不是 Merkle 树。它提供高效的顺序验证,却不能为任意条目提供紧凑证明,也没有公共一致性协议。对于一台执行中等数量智能体操作的 Mac,这通常是合理的取舍。除非你有独立监控器、许多验证者,或需要证明某个条目属于大型共享日志,否则仅仅因为透明度论文中出现了 Merkle 这个词,就添加一项 Merkle 服务,属于不必要的复杂化。

设置锚点确实有成本。你必须管理另一个存储边界,决定检查点频率,处理故障,并保留足够的元数据,把检查点与本地日志关联起来。每次操作都创建检查点会带来大量通信和更多故障情况。每天创建一次检查点,则会留下很长的窗口,截断操作可能难以暴露。检查点间隔应与有害操作变得代价高昂的速度相匹配。

对于生产部署凭据,与其争论每天导出在技术上是否足够,我更愿意为每个完成的特权操作设置锚点。对于低风险的只读 API 调用,定期保存日志根可能就够了。

加密隐藏的是记录内容,不是历史

加密日志可以防止普通读者看到敏感操作详情,但加密本身无法说明记录是否发生过变化。团队经常构建了一种属性,却把它描述成两种属性,直到调查时才发现差异。

假设一条日志记录包含 HTTP 路径、授权凭据标签、请求元数据和返回的错误。加密这条记录,可以防止偷走磁盘的人知道智能体访问了哪个客户端点。但它无法阻止拥有特权的本地进程用另一段密文替换原来的密文。你需要对每条记录使用认证加密,并在密文记录之间,或在它们经过认证的表示之间建立哈希链。

更清晰的设计是,让完整性验证可以在不暴露内容的情况下进行。验证者读取加密记录序列,检查封装格式和前置记录关系,重新计算哈希链,并报告当前字节是否仍构成预期历史。它不需要解锁凭据保险库,就能判断记录 1042 是否仍然接在记录 1041 后面。

这种分离在遏制事件期间很有价值。调查人员可以复制日志、运行验证并保存结果,然后再请求任何人解锁敏感材料。负责第一轮事件调查的人,不应该为了判断证据是否被修改,就必须广泛访问部署凭据。

加密也迫使你做出保留决策。如果设备迁移后没人能解密旧记录,你的完整性证明可能仍然有效,但日志已经失去实际意义。恢复流程和保留流程应与审计格式分开。不要把解密密钥放在加密归档旁边,然后认为问题已经解决。

在 macOS 上,硬件支持的保护可以缩小本地密钥的暴露范围。Apple 的安全文档将 Secure Enclave 描述为一个隔离的硬件安全处理器,Apple 的开发者文档也指出,其中描述的 Secure Enclave 机制无法将明文密钥材料传入或传出。这有助于构建本地保险库,但不会自动认证 Mac 上的每个进程。

日志仍然必须标识哪个进程获得了批准,以及哪个操作越过了网关。硬件保护只能守住一个边界。审计证据需要守住多个边界。

失败通常在危险命令之前就开始了

检查日志链
哈希链会检测你保留的加密日志中是否存在顺序被篡改或记录被修改的情况。

一次看似合理的智能体事件,很少从一条明显恶意的命令开始。它通常始于一个平常的请求,却继承了过多权限。

设想一个编程智能体收到工单,要求它诊断一次失败的发布。它读取代码库,看到了部署脚本,然后向发布主机打开 SSH 通道。第一条命令没有危险:

systemctl status web.service

输出中包含一个临时配置文件的路径。智能体随后读取该文件,找到部署凭据引用,并运行第二条命令修改环境变量。远程命令返回退出码 0。二十分钟后,一位客户报告请求失败。

控制措施可以在哪里阻止或暴露这次操作?

首先,保险库网关可以在锁定状态下阻止所有外部操作。它无法判断命令是否明智,但能防止后台智能体在用户关闭安全边界后继续使用凭据。

其次,会话授权可以在第一次操作前显示智能体进程的身份。这正是代码签名授权重要的地方。一个熟悉的编辑器进程和一个从 /tmp 启动的未签名辅助程序,即使它们都使用 MCP,也不应仅因此获得同等对待。

第三,对发布主机凭据设置审批要求,可以在第二次操作时中断流程。提示应展示足够的目标和操作上下文,让人看出这已经不再是诊断。一个笼统的「允许 SSH」按钮达不到这个标准。

最后,日志必须将两条命令记录为同一运行任务下两个独立的已完成操作。如果事件记录只有「智能体调查了部署故障」,就会掩盖运行从观察转向修改的那个时刻。

对于能够改变生产状态的凭据,我倾向于每次使用都要求审批。这会更慢,但也会迫使人面对诊断任务越过边界、变成实际操作的具体时刻。

不要为每个无害请求都要求点击。人们会在一长串相同提示面前不加阅读地全部批准,毕竟界面会教会他们这样做。应把阻力放在凭据使用上,因为每次调用的影响范围都可能不同。

进程身份必须写入记录

一条只写着「Claude Code 使用了 SSH」的审计轨迹,太模糊,无法解决争议。你需要知道哪个本地进程启动了运行任务,操作系统报告了什么签名授权,以及审批是否覆盖了这个进程实例。

这里还有一个常被混淆的定义:应用身份不等于进程身份。品牌名称可以指向一个合法产品,但被入侵的扩展、复制出来的二进制文件或 shell 包装器,也可能从不同的可执行文件上下文调用同一个协议。审批决定应绑定到实际请求操作的进程,并在该运行任务退出时失效。

日志应保存稳定的运行标识符以及足够的进程来源信息,以便之后回答这些问题:

  • 第一个请求和最后一个请求是否由同一个进程发出?
  • 用户是否在调用发生前批准了这次运行?
  • 在后续请求到达之前,这次运行是否已被撤销?
  • 是否有无关的本地进程试图复用该通道?

不要把可变的显示名称当成最重要的身份字段。名称会改变,路径也可能被替换。签名授权或同等的平台身份更有用,因为它能把审批界面、会话日志和之后的调查连接起来。

这需要付出代价。合法的开发构建、本地分支和未签名工具会带来更多审核工作。这不是审计模型的缺陷,而是允许实验性软件访问真实凭据所必须承担的成本。应考虑让这些工具使用单独的低权限凭据,而不是教会审核人员忽略陌生的身份详情。

记录还需要区分被拒绝的尝试和已完成的操作。被拒绝的 SSH 请求说明控制措施正在发挥作用。连接失败说明有人尝试过这条路径,但不能证明远程执行发生过。带有返回结果的已完成请求,证据强度更高。不要把这些结果都压缩成一个名为 success 的布尔值。

用一份日志记录运行和调用,时间线会更清晰

批准实际运行的进程
新智能体进程发起的首次调用会显示其代码签名权限,供你批准会话。

会话事件和操作事件应该从同一个有序事实源中生成,尽管运维人员阅读它们的目的不同。在压力下,由不同组件写入的独立日志文件很容易彼此偏离。

会话视图回答智能体生命周期相关的问题:运行何时出现、属于哪个进程、是否得到用户授权,以及是否有人撤销了它。活动视图回答单个操作相关的问题:选择了哪个凭据标签、使用了哪个目标地址、调用是否获准,以及返回了什么结果。

这两种视图不应成为彼此独立的来源。如果某个操作没有对应会话,或已撤销的运行任务看起来仍在继续发出调用,调查人员需要通过同一个序列判断这是数据不一致,还是系统行为本身有问题。

这正是一个写入盲的加密日志具有实际优势的地方。各组件可以追加它们有权报告的信息,同时日志格式又能防止它们随意浏览不相关的记录。安全收益不在于让日志变得神秘,而在于减少可以读取、编辑和重新解释历史记录的代码路径。

Sallyport 会从一份加密、哈希链式审计日志中生成 Sessions 日志和 Activity 日志,而 sp audit verify 可以在不解锁保险库的情况下,离线对密文执行哈希链验证。这正是本地智能体证据应该具备的形态,因为在遏制事件期间,验证路径仍然可用。

对于后果严重的环境,我仍然会导出检查点。本地验证只能告诉你手上的副本在内部是否完整。外部检查点则有助于发现有人交给你的是更旧、更短的历史。

让日志展示与日志事实保持分离。日常使用的便捷界面可以筛选、分组和编辑记录。底层验证器必须依据稳定字节和确定性顺序工作,而不能依赖当前界面碰巧展示的内容。

验证应该成为日常流程,而不是仪式

只有事件发生后才运行的验证命令,是一个没人测试过的功能。应把它纳入日常维护,并让失败处理变得清晰可预期。

对于 Sallyport 安装,第一项具体检查是:

sp audit verify

在重大升级前、抹掉开发 Mac 前,以及怀疑本地状态发生异常变化时,对复制出的日志运行验证。保存你实际验证过的那份日志副本。之后在另一份副本上重新运行命令,无法证明事件发生时原本存在什么。

单靠命令还不够。应配合一套简单的操作流程:

  1. 在修复之前,保留日志副本及其检查点引用。
  2. 记录受影响的运行标识符和正在调查的时间范围。
  3. 将已完成的 HTTP 和 SSH 操作与远程服务提供商自己的日志进行比对。
  4. 在让智能体执行清理之前,先撤销正在运行的任务。
  5. 导出或传输后再次验证,确认复制出的证据没有损坏。

第三项很重要,因为本地完整性和外部事实互为补充。有效日志可以显示网关发出了 POST /deployments,部署服务提供商则可以显示它接受、排队还是拒绝了这项操作。SSH 退出状态可以说明 shell 命令已经完成,主机服务日志则可以显示之后实际运行的进程。

我对只能在仪表板中展示事件的审计系统没有耐心。如果不依赖仪表板就无法验证存储的日志,那么事件响应就依赖于同一套可能正在被调查的应用程序栈。

对于缺失分段、无效序列号、格式错误的密文封装,或前置记录不匹配,验证都应该明确失败。一个为了生成更漂亮的时间线而跳过坏记录的工具,只是一个态度礼貌的证据粉碎机。

审批记录需要和操作记录一样严谨

追踪调用中的运行过程
会话和单次调用来自同一有序审计源,因此时间线始终连贯。

一次审批点击属于安全事件的一部分,而不是装饰性的界面细节。如果系统只记录某项操作被允许,就无法在之后确认用户批准的是某个特定运行、某类凭据,还是完全不同的提示。

保存当事人实际看到的决策上下文:请求进程的身份、审批范围、相关凭据标签和时间。对于会话级决定,记录会话开始的时间,以及结束或被撤销的时间。对于每次使用的决定,将审批绑定到一次具体的操作尝试,避免它悄悄授权后续的其他目标地址。

良好的审批边界包含一个直接的取舍。更宽泛的会话授权可以减少打扰,让自主循环更易用。更窄的逐次调用授权给人更多机会阻止错误方向,但如果用于日常读取操作,就会让人疲惫。没有哪种设置绝对更安全,合理范围取决于凭据的实际影响。

通常,三项控制就够了:在用户打开保险库之前保持锁定,为一个会话授权一个已识别的进程,并对指定凭据的每次使用要求明确确认。规则语言看起来可能更复杂,但每个条件都会变成发布时必须测试的另一项声明。对于桌面操作网关,我会选择一组小而固定的控制,而不是一套凌晨两点没人能解释清楚的策略引擎。

这个选择会排除一些工作流程。固定的决策阶梯无法表达所有环境例外或基于时间的策略。拥有服务器集群和复杂委派需求的团队,可能需要另一种系统。假装一个本地菜单栏应用应该变成通用授权服务器,结果就是让原本专注的安全边界变得脆弱。

在授予访问权限前,先决定你需要证明什么

真正有用的问题不是「我们有日志吗?」而是「这次运行出错时,我们需要证明哪项事实?」

针对智能体可能使用的每个凭据,用简单语言写出要证明的事实。例如:这个经过签名的进程获得了这次运行的授权;这次运行调用了这个 API 端点;这个 SSH 命令越过了本地网关;被拒绝请求发生时该凭据处于锁定状态;自保留的检查点以来,这些记录没有被修改。

然后用棘手的场景测试日志。删除最后 50 行,修改一个目标地址字段,把日志复制到另一台 Mac,在锁定保险库后尝试验证,在两次调用之间撤销一次运行。如果你无法说清楚哪个控制应该阻止事件,以及哪条记录应该显示它,那么你拥有的是可观测性,而不是证据。

哈希链不会让不安全的凭据变得安全。加密无法证明完整性。审批提示也无法挽救一个漫不经心的审核人员。每项控制都有更狭窄的职责。

在操作发生的位置生成记录,保护记录内容,按顺序建立哈希链,在写入者之外保留锚点,并在智能体接触任何可能造成伤害的权限之前反复演练验证。这套流程不如庞大的策略引擎耀眼,但当有人问「实际运行了什么」时,它更容易解释,也更容易守住。

常见问题

什么是哈希链式审计日志?

哈希链会让后续修改变得可检测,因为每条记录都包含前一条记录的哈希值。但除非保留可信检查点或将日志复制到其他位置,否则它无法阻止有人删除整份日志,或提供一段较短但有效的前缀。

加密审计日志后,它就能检测篡改了吗?

不能。加密用于保护日志内容的机密性,哈希链则用于暴露存储序列是否遭到修改。当操作详情包含代码库名称、API 路径、命令参数或返回数据时,通常应同时使用两者。

AI 智能体审计轨迹应该记录什么?

记录智能体进程身份、授权决定、操作类型、目标地址、使用的凭据标签、规范化的请求摘要、结果状态、时间戳以及稳定的运行标识符。默认情况下,避免记录原始密钥或完整响应正文。

哈希链能证明 AI 智能体执行了它声称的每个操作吗?

它可以证明存储的日志在不破坏哈希链的情况下没有被修改。但除非系统同时防止遗漏、截断和多套日志视图,否则它无法证明日志包含了所有操作。

为什么要为智能体分别保留会话日志和操作日志?

会话日志回答谁启动了任务、运行的是哪个可执行文件,以及任务是否被撤销。调用日志回答具体哪个 HTTP 请求或 SSH 命令越过了操作边界。两者都需要,因为完整的会话历史仍可能隐藏某个危险的单独调用。

不解密也能验证加密审计轨迹吗?

可以让日志静态加密保存,并尽可能直接对密文验证其加密结构。这样,调查人员无需仅仅为了验证证据而解锁凭据,也能检查日志是否损坏或被修改。

智能体对话记录足以应对合规或事件响应吗?

除非文本记录由实际执行操作的组件生成,并且与受完整性保护的日志绑定,否则应把它视为调试材料,而不是安全证据。智能体的自述很容易在出错后被遗漏、改写或伪造。

什么时候应该要求 AI 智能体每次操作都经过审批?

对于生产部署、破坏性数据库操作、权限变更和陌生目标地址,每次调用审批都值得付出额外打扰。对每次无害的读取操作都要求审批,通常会让人形成机械点击的习惯,因此应把它保留给每次使用都带有独特风险的凭据。

如何调查可疑的 AI 智能体操作?

在开始清理之前,先从副本验证日志,收集相关会话标识符和周围记录,然后将操作序列与服务提供商日志及代码库历史进行比对。在保全证据之前,不要让智能体先替你总结事件。

检测篡改的日志能取代访问控制吗?

不能。哈希链用于事后证明证据完整性,授权控制则决定高风险操作是否可以发生。一个团队即使安装了完美的日志系统,却让未经审核的进程使用生产凭据,也只是把自己的错误记录得非常整齐。

Sallyport

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

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