阅读需 8 分钟

代理审计日志:会话记录与调用记录

代理审计日志需要会话记录来说明权限,也需要调用记录来记录每次外部操作。了解两种视图如何加快事件响应。

代理审计日志:会话记录与调用记录

代理审计日志在把两个不同问题塞进同一条记录时就会失效。发生事件时,你需要同时确认谁拥有执行权限,以及到底有什么操作触达了外部世界。运行记录不能代替调用记录,请求列表也无法解释为什么那个进程拥有权限。

团队常常只保留其中一种视图,因为在演示时,一种视图看起来已经够用了。可一旦代理创建工单、更新生产设置或运行 SSH 命令,调查就会沦为猜测时间戳。这完全可以避免。用会话日志记录权限和生命周期,用活动日志记录每一次尝试执行的外部操作。再用一个由系统分配、不能由人或代理随意编造的标识符把两者关联起来。

运行记录回答谁拥有权限

会话记录应回答:某个特定代理进程是否有权执行操作,权限持续了多久,以及背后依据的是哪项人工决定。当有人问「哪个代理实例做了这件事,为什么我们允许它这样做?」时,你就要查这条记录。

有用的会话记录应从进程第一次请求权限时开始,而不是从用户打开编辑器时开始,也不是从项目目录出现时开始。代理名称的证据价值很弱。两个进程可以使用同一个名称,恶意二进制文件也可以借用一个熟悉的名称。应记录主机能够提供的进程身份、操作系统支持时的代码签名权限、必要时的父进程、生成的会话 ID、开始和结束时间,以及授权结果。

会话记录还需要生命周期事件。批准是一项事件,撤销是一项事件,进程退出也是一项事件。如果锁定凭据库会阻止活动,那么锁定也值得记录并关联。没有这些边界,调查人员就无法判断某次调用发生在批准期间,还是发生在所谓的关闭之后。

不要把会话记录变成每个模型思路、每一行终端命令和每次文件编辑的日记。这样会堆积大量敏感材料,却仍然漏掉真正重要的边界:代理进程获得权限,可以请求网关执行外部操作。应清楚地记录能够确立这条边界的证据。

下面是一条简化的会话记录:

{
  "type": "session.authorized",
  "session_id": "ses_7f4c2",
  "observed_at": "2025-04-18T14:03:11Z",
  "process": {
    "pid": 8124,
    "signing_authority": "Example Development Team",
    "parent_pid": 8090
  },
  "decision": "approved",
  "approved_by": "local_operator"
}

会话记录不需要员工姓名也能发挥作用。在共享工作站上,local_operator 可能就是诚实的归因粒度。假装掌握更多信息,只会制造自信的虚构。如果你的环境可以把批准绑定到经过身份验证的人员,就记录这种绑定,以及建立绑定的方式。

会话记录绝不能声称整个运行过程都是安全的。批准授予的是权限,并不是预先批准进程可能产生的每一种影响。这个区别听起来很细,但当编程代理让会话持续数小时并在一次批准下发出数百次调用时,它就非常重要。

调用记录回答什么触达了外部世界

调用记录应描述一次操作尝试及其结果。当有人问「代理是否发出了这个请求,目标是什么,结果如何?」时,你需要的就是这条证据。

记录尝试,而不只是记录成功。被拒绝的请求可能表明代理正在探测凭据。失败的请求可能说明主机名称拼写错误、机密已过期,或远程端拒绝了不安全的命令。取消的请求可以解释为什么一次会话看起来在部署中途停止。只记录成功的日志讲述的是一个好听却不完整的故事。

对于 HTTP 操作,应保留目标身份、HTTP 方法、路径或受控的路径表示、凭据引用而不是凭据值、请求时间、完成时间、状态结果、会话 ID 和调用 ID。对于 SSH,应保留预期的主机身份、命令或安全的命令表示、连接结果、可用时的远程退出状态、会话 ID 和调用 ID。

应谨慎决定保留哪些请求数据。习惯性记录完整请求头和正文,迟早会引发事件。授权请求头、Cookie、签名 URL、访问令牌、客户隐私数据和密码经常藏在其中。好的记录应保留操作含义,同时删去机密材料。例如,POST /v1/users/123/disable 可能已经足够还原一次管理变更,而复制完整 JSON 正文可能会暴露远超调查所需的信息。

记录目标身份,不要只记录原始 URL 字符串。https://api.example.testhttps://api.example.test:443 可能代表同一个目标,而仿冒主机名可能只差一个字符。对于 SSH,在系统能够获取时,记录用于验证的主机身份。仅凭主机名,无法确定连接是否到达了预期机器。

下面这组配对记录展示了两者的区别:

{
  "type": "call.completed",
  "call_id": "call_b91d",
  "session_id": "ses_7f4c2",
  "observed_at": "2025-04-18T14:09:27Z",
  "channel": "http",
  "operation": "POST",
  "target": "api.example.test/v1/deployments/42/cancel",
  "credential_ref": "deployment-service",
  "authorization": "session_approved",
  "outcome": "completed",
  "response_status": 202
}

会话 ID 说明这次调用使用了谁的权限。目标和结果说明发生了什么。如果把它们合并成 agent performed task 这样的模糊事件,两个问题都没有得到很好的回答。

批准和执行是两件不同的事实

团队常常把批准事件误认为请求实际运行的证据。两者是不同的事实,审计轨迹必须同时保留。

操作员可能批准了一个新的代理进程,然后离开。进程可能因为任务在本地完成而没有发出任何调用,也可能发出一次失败的 API 请求,或者发出五十次成功请求。三种情况下,批准记录都不变。只有单独的调用记录才能显示实际影响。

反过来的混淆也会发生。有人在网络日志中看到一个出站请求,就认定它是由获批代理发出的。网络日志可以证明连接或请求片段,具体取决于采集位置。它通常无法显示批准决定、实际进程身份,或网关是否代表代理注入了凭据。不要强迫网络日志回答它从未被设计来回答的问题。

NIST Special Publication 800-92《Guide to Computer Security Log Management》区分了事件源、日志基础设施和分析流程。对代理系统来说,它的实际启示很直接:在掌握事实的那一层采集事件。授权层知道会话是否获得了权限,操作网关知道它使用受保护凭据尝试了哪项操作,防火墙知道它观测到的流量。每种记录的证据范围都不同。

在每次调用上记录准确的授权状态很有帮助。session_approved 表示会话拥有持续有效的批准。per_call_approved 表示操作员批准了这次使用。denied_locked 表示凭据库锁定时拒绝了尝试。denied_user 表示操作员拒绝了请求。这些不是装饰性标签,它们能告诉调查人员操作是否到达执行器,以及是否由人工干预将其阻止。

不要把每次成功调用都标成「已批准」。这个词会掩盖会话开始时授予的权限,与实际使用时授予的权限之间的区别。当事件复核人员问「有人批准删除操作吗?」时,记录应当让人一眼就能得到答案。

逐次调用审批有其适用场景,但应把它作为范围有限的控制措施。对于每次使用都影响重大,或会改变目标状态且操作员应当看到的凭据,可以启用它。如果连日常读取和无害的构建调用也要求人工点击,人们很快会习惯性批准一片提示。纸面上仍然有批准,但它已经不再代表知情同意。

失败时间线能揭示摘要掩盖的缺口

只要建立一条事件时间线,就能明显看出两种视图的价值。假设一个自主编程代理接到任务,要清理过期的预览环境。操作员批准了它在本次会话中运行。代理发现一个旧的部署 API 凭据,并请求网关使用它发出调用。

14:03,会话日志记录一个获批进程,并分配 ses_7f4c2。14:07,活动日志记录一条列出部署的 GET 请求。14:09,记录了上面展示的取消调用。14:10,第二次取消尝试收到 403 响应。14:12,操作员发现代理选择了错误的环境组,于是撤销会话。

现在假设你只保留了会话记录。你可以说某个进程被批准,之后又被撤销,但无法确定它取消了一个、多个还是零个环境。你也无法区分第二次尝试是被阻止还是成功了。你只能去询问部署服务,而它的日志保留时间或请求细节可能无法满足需求。

再假设你只保留调用记录。你可以看到两次取消请求,但无法确定是哪一个本地进程发起的,也无法确定操作员是否批准了该进程、批准在当时是否仍然有效,或操作员是否在撤销后及时采取了行动。

时间线应保留事件顺序,但不要假装墙上时钟绝对准确。机器会发生时钟漂移,远程服务也会报告自己的时间戳。网关观测到请求时写入网关时间戳,并在相关情况下单独保留远程结果时间戳。如果审计日志有内部排序序列,也应使用它。不要仅仅因为两个事件在时钟上共享同一秒,就宣称它们存在因果关系。

一个棘手的问题是,撤销会话后,调用是否仍可能完成。答案是可能,具体取决于撤销何时到达执行器,以及请求是否已经离开机器。记录应让这一点清晰可见。记录撤销时间,然后记录之后完成的任何调用,同时注明调用的开始时间和完成时间。简单删除会话的系统会让这种分析变得不可能。

关联 ID 需要严格归属

审批你看到的进程
每会话审批会在你批准运行前显示进程的代码签名权限。

只有在网关分配并控制会话 ID 时,它才有意义。不要让代理提供会话标识符,再把它当作安全证据。

代理可以在工具调用之间携带任意文本。它可能在重启后重复使用旧 ID、输入错误的 ID,或者在接口允许时故意冒用另一个会话的 ID。网关必须根据经过身份验证的本地连接或进程关系推导关联,然后自行把会话 ID 附加到每次调用上。

调用 ID 也需要同样处理。在请求离开前、位于操作边界处生成调用 ID。如果 HTTP 请求发生重试,应记录这是一个与原调用关联的新尝试,还是同一个调用中的多次传输尝试。两种模型都可以,但混用会在中断期间破坏计数准确性。

使用小而一致的关联模型:

  • 会话 ID 将一个代理进程的权限和生命周期事件归为一组。
  • 调用 ID 标识一次请求的外部操作。
  • 尝试 ID 在重试重要时标识一次传输尝试。
  • 凭据引用标识已配置的机密,但不暴露其值。
  • 目标引用标识主机、服务或命令目标。

不要要求每个标识符对人类都具有全局意义。它们的任务是可靠地关联记录。可读标签可以与它们并列,但标签会变化、冲突,也容易被随意编辑。

对于并发代理,关联机制可以避免一种常见错误。工程师看到 16:21 的破坏性请求,又找到一个 16:21 的代理终端记录,于是认定两者对应。与此同时,另一个代理进程可能也在同一账户下运行。操作记录中的会话 ID 可以消除这种猜测。如果不存在稳定的关联方式,就在事件报告中明确说明这一限制,不要用自信填补空白。

审计日志必须同时显示拒绝和使用

被拒绝的操作有时比已完成的操作更重要,因为它们能揭示代理在控制措施阻止之前试图做什么。应记录足够的上下文来解释决定,同时避免让拒绝日志变成新的机密泄露源。

锁定的凭据库应拒绝所有需要凭据的操作。生成的调用记录应说明操作在外部执行前就被拒绝,标明请求的会话和目标,以及原因类别。记录中不应出现伪造令牌、部分私钥或复制来的授权请求头。

逐次调用拒绝也需要同样谨慎。如果操作员拒绝了一条 SSH 命令,应记录命令表示、目标、会话、决定时间和决定结果。此时缺少远程退出状态就有了明确含义:执行器从未启动该命令。这与命令已经启动但返回非零状态不同。

Sallyport 使用三项固定控制:绝对凭据库闸门、默认的每会话授权,以及可选的单凭据逐次调用审批。这种边界清晰的模型让审计解释更容易,因为每条记录都可以指出是哪项决定阻止或允许了操作。

不要为每个代理操作都采用一个庞大的策略语言。这种做法很流行,因为它承诺完全自动化。实际上,策略引擎会增加第二套程序,团队必须在事件期间对它进行审查、测试、更新和解释。如果网络或服务治理需要策略,就在相关层使用它们。不要假装一组无法读懂的规则可以替代清晰的会话和调用证据。

记录应区分以下结果:

  • 代理从未拥有经过授权的会话。
  • 会话拥有权限,但凭据库处于锁定状态。
  • 网关请求逐次调用决定,操作员拒绝了它。
  • 网关执行了操作,但远程目标拒绝或执行失败。
  • 网关执行了操作,并获得成功结果。

这些情况需要不同的后续处理。会话请求被拒绝可能指向不受信任的进程,远程 403 可能指向凭据权限范围问题,而成功但不符合预期的调用,可能需要复核任务指令、会话批准决定,以及目标凭据允许的用途。

篡改证据保护事件之后的记录

在网关分配会话
捆绑的 MCP shim 会在代理进程使用受保护凭据前,将其绑定到一个会话。

普通应用日志很容易在有人控制主机后被编辑、截断或替换。这不代表它们毫无用处,但会限制它们能够证明的内容。采用哈希链的审计日志,可以让验证者将链与收到的记录进行比对,从而发现后续修改。

这个区别很重要。哈希链可以表明保留下来的链中某条记录被修改,或中间有记录消失。它不能证明系统记录了所有本应存在的事件,也无法挽救在创建事件之前就已被入侵的主机。它还不能告诉你操作员是否理解了一张审批卡片。超出这些范围的说法,都是安全表演。

RFC 5848《Signed Syslog Messages》讨论了相关问题:日志消息在系统之间传递时,可能失去完整性和来源保证。即使使用的是本地加密日志而不是 syslog,它的启示仍然适用。在事件发生点附近保护日志,保留顺序证据,并进行验证,而不是只相信一个漂亮的界面。

Sallyport 将 Sessions 日志和 Activity 日志都写入同一个不可写入、加密并采用哈希链的审计日志。其 sp audit verify 命令可以在离线状态下对密文验证链,无需凭据库密钥。当复核人员需要验证记录完整性,却不应获得执行操作所用的机密时,这项功能很有用。

在筛选、导出或为事件添加注释前,先运行验证。先保留原始加密证据,再复制一份工作副本进行分析。如果验证失败,应记录失败情况和检查过的确切工件。不要悄悄继续使用清理后的导出文件,因为完整性问题本身已经成为事件的一部分。

篡改证据也会改变日常纪律。如果团队知道后续编辑会留下痕迹,就不会再把审计日志当作部署失败后改写历史的方便位置。这本身不能阻止错误,但能保留从错误中学习所需的证据。

保留期限需要边界,而不是不加区分地采集

保留撤销边界
会话可以立即撤销,同时日志会保留调查人员需要的生命周期证据。

会话和调用记录应保留足够长的时间,以调查延迟发现的问题、凭据滥用和访问复核。但不要因为存储便宜,就永远保留所有正文。最危险的日志往往是那些没人分类的日志。

先从团队必须回答的事件问题开始。代理运行后多久,服务负责人可能发现不应有的变更?员工离职后,需要追踪凭据使用多久?哪些法规或合同规定了保留期限?这些答案决定保留时间,但并不意味着你应收集不需要的原始提示、完整响应或机密。

把运营可见性与取证保存分开。操作员可能需要查看活动会话和近期调用的简洁当前视图,调查人员则可能需要完整且不可变的序列,包括拒绝和详细时间信息。让每个开发者都能无限制访问后者,会把审计轨迹变成另一份敏感数据集。

对复核设置角色边界,但不要把访问控制当作向事件负责人隐藏材料的理由。服务负责人可能需要知道某次调用修改了自己的服务,但不需要承载令牌或无关客户正文。

当记录指向存放在其他位置的敏感内容时,应保存受控引用和检索流程。例如,保留一个请求 ID,让目标服务可以按照自身访问规则定位受保护的正文。这样可以让操作日志保持有用,又不会把敏感业务数据复制到每个审计系统。

删除也需要自己的记录。如果保留期限导致一批记录过期,应在删除数据前记录保留事件、范围和触发删除的权限。否则,后续验证者无法区分经过授权的过期删除和无法解释的缺失。保留期限政策应足够易懂,让事件复核人员无需咨询原系统编写者就能执行。

从调用向外关联,建立事件视图

在进行中的调查中,应从可疑调用开始向外追查。调用通常是最具体的证据:它包含目标、操作、时间和结果。利用其中的会话 ID 找到权限记录,然后检查该会话附近的其他调用,以及会话的撤销或退出事件。

按以下顺序进行:

  1. 在编辑或导出原始审计记录前,先保留并验证它们。
  2. 按目标、调用 ID、操作或事件时间窗口定位调用记录。
  3. 找到关联的会话记录,确认进程身份、批准时间和生命周期状态。
  4. 查看该会话在事件前后的每次调用,包括拒绝和重试。
  5. 将操作时间线与目标服务自己的记录进行比较,并记录缺口,不要猜测填补。

这种方法既能发现明显错误,也能发现更隐蔽的问题。明显错误是本不该发生的调用,隐蔽错误则可能是任务结束后会话仍然保持授权,或服务超时后重试导致操作重复。

不要因为轮换所有凭据看起来果断,就先这么做。如果凭据库一直没有把凭据交给代理,而记录显示网关只向一个已知目标发出调用,那么大范围轮换可能只会制造不必要的中断。如果仍可能发生滥用,应立即撤销有效会话。然后利用调用记录决定具体需要处理的是哪个凭据、目标或访问范围。

两种视图确实会产生更多记录,但它们也能消除事件报告中代价最高的一句话:「我们无法确定获批代理是否真的做出了这项变更。」在会话边界让权限可见,在调用边界让影响可见。少了其中任何一项,你的团队都只能从零散痕迹中重建安全事件。

常见问题

代理会话日志和操作日志有什么区别?

会话记录描述一个代理进程或一次运行,包括谁启动了它、如何识别它、何时开始和结束,以及操作员是否批准或撤销了它。调用记录描述一次具体的外部操作尝试,例如 HTTP 请求或 SSH 命令。两者都需要,因为一次受信任的运行仍然可能发出不安全的调用。

AI 代理只需要会话审批就够了吗?

不够。会话级审批只能说明你是否允许某个代理进程在其生命周期内执行操作。它无法说明这次运行中的每个目标、请求、命令、响应状态和失败结果是否都可以接受。

发现可疑的代理操作后,应该先查看哪种日志?

先查看单次调用记录。它会告诉你目标、操作、时间、结果,以及发出请求的会话。然后查看会话记录,确认哪个进程拥有权限,以及有人是在调用之前还是之后撤销了该权限。

应该如何关联会话记录和调用记录?

两者应通过稳定的会话标识符关联,并且每次调用都记录该标识符。不要主要依靠时间戳、进程名称或猜测的用户身份进行关联。这些字段有助于调查,但当多个代理同时运行时,无法可靠地证明因果关系。

被拒绝的代理操作也应该写入审计日志吗?

每次调用尝试都应记录,包括被拒绝、取消和失败的请求。只记录成功操作的系统会掩盖权限探测、格式错误的命令、过期凭据,以及操作员及时阻止的尝试。

什么时候应该要求 AI 代理为每次 API 调用单独审批?

对于单次使用可能造成 disproportionate harm 的凭据或操作,逐次调用审批很合适,例如生产环境删除操作或资金转账。它应当补充会话授权,而不是取代会话授权。如果连日常低风险调用也要求审批,操作员会产生审批疲劳,最后不看内容就点击批准。

采用哈希链的审计日志能证明没有遗漏任何事件吗?

如果验证者拥有预期的哈希链和可信的起点,哈希链可以让后续篡改变得明显。它无法证明记录的事件是完整的,也无法证明采集时机器没有被入侵,更无法证明人类真正理解了授权内容。篡改证据很有价值,但不是万能证据。

AI 代理审计轨迹应包含哪些字段?

应保留足以还原权限和操作的上下文:进程身份、会话 ID、操作类型、目标身份、时间戳、授权决定、结果和关联 ID。不要把原始 API 密钥、SSH 私钥、承载令牌或敏感请求正文放入普通审计记录。

应该如何审计编程代理执行的 SSH 命令?

SSH 命令应生成一条调用记录,其中包含目标主机身份、命令或受控的命令表示、会话 ID、授权状态、时间信息、退出结果,以及可以安全保留的失败详情。记录必须表明网关执行了命令,同时不能让代理接触私钥。

代理发出意外的外部调用后,团队应该怎么做?

先验证哈希链,保留原始记录,确认会话边界,然后再建立调用时间线。若代理仍可能运行,应撤销有效权限。之后只根据记录显示的可能暴露或滥用范围轮换或限制凭据。没有时间线就大范围轮换凭据,往往会在制造第二次中断的同时破坏有价值的证据。

Sallyport

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

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