# 每周代理安全审查：一套实用的 35 分钟流程

一次**每周代理安全审查**应在一小时内完成，得出少量明确决定，并留下日后可以检查的证据。如果审查变成在数千条记录中漫无目的地寻找，连要回答的问题都不清楚，那么设计从一开始就失败了。

我见过团队在自动化工作上犯同一个错误：他们知道应该收集活动记录，于是把记录存了下来，却只在发生令人不安的意外后才打开查看。到那时，有用的上下文已经失效。发起运行的工程师已经转去处理别的任务，临时凭证也已经消失，没有人说得清那条奇怪的命令究竟是一次合理修复，还是权限边界出现问题的第一个信号。

每周检查解决的是一个更具体的问题。它能在人和任务仍然容易识别时发现访问权限逐渐偏离。它也会迫使团队区分一个经常被混淆的事实：代理被允许执行某项操作的记录，并不等于该操作本身合理的记录。

## 每周审查能在偏离变成常态前发现问题

每周审查之所以有效，是因为代理权限往往通过一些容易被遗忘的小变化逐渐扩大。有人为了让测试通过，添加了一个令牌。一个编程任务扩大成了部署变更。代理不断重试 API 调用，直到备用路径成功。这些事件单独看未必值得启动事件响应，但连续几周累积后，可能形成一个没人有意批准过的访问模式。

实时审查每个事件听起来更安全，但大多数团队无法长期保持所需的注意力。审查人会开始按照模式批准或驳回记录。他们不再追问，为什么一个正在编辑文档的代理连接了生产主机。这其实是披着安全外衣的审批疲劳。

等到季度审查则会因为相反的原因失败。一个季度包含太多运行、太多变更过的代码库，也包含太多已经模糊的记忆。最后你只是在统计事件，而不是理解事件。

设定固定的每周时间窗口，每次在同一时间审查前七天。选择审查人能够联系执行异常任务的人员的时段。有些团队适合周五下午。如果周末自动化任务需要关注，周一早上可能更好。具体日期不如保持稳定重要。

审查应回答五个问题：

- 哪些新的代理进程获得了权限？
- 哪些操作偏离了任务要求或正常目标？
- 哪些失败说明集成出现问题，或存在探测行为？
- 哪些会话被人撤销，撤销是否真的阻止了后续使用？
- 哪些凭证需要负责人在下次使用前做出决定？

不要因为仪表板能显示某项数据，就额外增加第六个问题。每周流程只有在契约明确且范围有限时才能持续。一旦变成屏幕上放着日志的泛化安全会议，它就会逐渐失去作用。

NIST SP 800-92，《计算机安全日志管理指南》强调了一点，这里依然适用：组织需要明确的日志分析流程，而不只是一个存放日志的地方。代理记录让这一点更加明显，因为代理可以快速而反复地行动。存储提供证据，流程则让证据有机会改变决定。

## 先看新会话，不要从单个调用开始

先审查新会话，因为会话是权限开始生效的单位。你需要知道哪个进程获得了权限、它以什么身份出现、运行何时开始，以及这次运行是否有合理的目的。

会话审查不是清点库存。不要看一眼列表，认出一个熟悉的开发者姓名，然后继续往下看。经过签名的进程身份能提供有关进程的信息，却不能说明这个进程是否因合理任务而启动。把进程身份当作来源证据，而不是意图证据。

对每个新会话，在审查记录中回答以下问题：

1. 谁发起或负责这次运行？
2. 哪个代码库、工单、维护任务或调查为它提供了理由？
3. 这次运行可以使用哪些类别的凭证？
4. 任务结束时，会话是否也结束了？
5. 是否出现了另一个使用不同身份、重复执行同一工作的会话？

最后一个问题能发现团队经常漏掉的一类故障。工程师发现工具在受限账户下失败，于是通过另一个代理进程重新运行并得到结果。活动记录可能只显示两个普通会话，但安全含义不同：第一个边界正确发挥了作用，第二次运行却可能绕过了设置该边界的原因。

如果会话没有可识别的负责人、没有任务引用、持续时间异常，或拥有与所述工作无关的权限，就标记为需要跟进。持续时间异常不代表所有长时间运行都可疑。大型重构和缓慢的测试套件本来就可能运行很久。一个在人类上下文已经消失很久后仍保持活动的会话值得关注，因为过期权限很容易被遗忘。

按用途维护一份小型的常规自动化许可清单，不要使用「可信」这样的模糊标签。例如，定期依赖更新任务可以合理地访问软件包仓库并创建拉取请求。这样的描述给审查人留下了可验证的依据。「可信编程机器人」则什么也没有说明。

## 异常命令需要上下文，而不是先追责

一条异常的 SSH 命令或 HTTP 请求是需要调查的证据，不是结论。审查人在这件事上常常会走向两个极端。有些人因为代理已经获授权，就忽略奇怪命令。另一些人把所有陌生命令都当作恶意行为。这两种反应都会让日志失去价值。

根据任务建立预期上下文。读取暂存环境部署状态的请求，可能适合发布调查。在调整 README 的任务中出现同样的请求，如果没有解释就不合理。归档构建输出可能很普通。归档用户主目录、读取 shell 历史记录，或修改远程启动文件，则需要仔细查看。

对于 SSH 活动，比较以下四个边界：

- 任务本应访问的主机。
- 任务实际需要的账户和目录。
- 任务允许进行的变更类型。
- 命令成功后预期产生的后果。

第四个边界很重要。在构建主机上执行 `git status`，后果通常很小。编辑服务定义、改变文件所有权或创建定时任务的命令，则会改变未来行为。这些调用应有具体任务引用和明确负责的人。

HTTP 记录也需要同样处理，只是线索有所不同。查看目标、请求方法、路径、响应类别和请求量。对预期服务发起新的 `GET` 可能很正常。大量收到授权失败响应、尝试访问管理路径，或向与任务无关的服务发起写入请求，都需要解释。

不要建立一份庞大的禁用字符串清单，然后把它叫作审查。代理可能在不合适的上下文中调用合法工具，而一条无害命令如果缺少参数信息，也可能看起来很吓人。审查人需要足够的周边证据，才能判断代理试图做什么。

一条有用的发现记录可以这样写：「会话 S-184 执行了一项代码库维护任务。它通过 SSH 访问部署主机，并修改了服务配置。任务记录没有包含部署工作。会话负责人确认这是误选命令造成的变更。我们撤销了该会话，并恢复了之前的配置。」这样的记录包含事实、解释和已完成的行动，其他审查人也能看懂。

较弱的记录则是：「发现可疑命令。」这句话只会制造焦虑，还会让下一位审查人重新还原整个事件。

## 失败调用既能显示故障，也能显示边界测试

失败调用值得单独审查，因为失败传递的信号与成功操作不同。成功写入可能改变系统，失败则可能暴露代理尝试访问一个本不应考虑的目标。

先把普通集成故障和可疑重复行为分开。过期令牌、变更后的 API 路径、网络超时或服务提供商限流，都会在正常工作中产生失败。修复可能属于运维问题，而不是安全问题。记录失败趋势，找出负责人，并在代理学会绕过故障路径前修复它。

然后查看会改变判断的模式：

- 同一个被拒绝的调用反复出现，期间没有有效退避，也没有任务变化。
- 代理在授权被拒后尝试相邻路径。
- 运行在被拒绝后改变目标，而不是报告拒绝结果。
- 失败调用的目标超出了任务边界之外的主机、服务或账户。
- 失败调用出现后，紧接着通过权限更宽的凭证成功执行操作。

最后一种模式往往隐藏着薄弱的凭证设计。假设代理尝试通过权限受限的令牌更新部署，却收到授权错误。随后它使用通用运维令牌并成功。日志可能显示这是一次「恢复成功」的任务，但审查应将其标记为权限范围失败。受限令牌正确拒绝了请求，宽权限令牌却掩盖了任务与允许访问范围之间的不匹配。

不要告诉团队每次 API 请求返回 401 或 403 就轮换凭证。这种建议很受欢迎，因为它看起来果断，但也很浪费。轮换无法修复缺失的权限范围、错误的端点，或代理反复选择错误操作的问题。它还可能用一个权限同样错误的新凭证替代证据链，让下一次审查更困难。

相反，把失败调用归入四种结果之一：预期的运维失败、配置缺陷、任务边界违规，或可能的凭证滥用。审查人应写明选择该类别的原因。如果证据不足以支持任何类别，就在运行情况仍然清楚时询问会话负责人。

## 撤销必须关闭引发担忧的路径

被撤销的会话应阻止活动进程继续使用已授予的权限，但它不会自动修复所有相关风险。每周审查需要检查撤销事件本身，以及周边的访问路径。

对每个被撤销的会话，记录触发原因。有人可能因为任务结束而撤销，也可能因为审批是误操作、进程身份看起来不对，或运行行为出乎预期。不同原因需要不同修复。正常的任务结束撤销可能无需进一步行动。异常进程身份则可能需要调查工作站和启动路径。

然后检查撤销后的活动。撤销后出现的任何调用都需要解释。它可能来自时间戳理解错误、独立获授权的进程，或审查人关联记录方式的缺陷。不要直接假定最坏情况，也不要轻描淡写地带过。撤销的意义在于让权限边界变得可观察。

还要检查并行权限。代理失去一个会话后，仍可能通过另一个活动进程、不同凭证、已打开的 SSH 连接，或独立的自动化账户继续行动。审查不需要证明整个公司不存在任何备用路径，但应确定同一任务是否能通过一个明显且未关闭的路径继续执行。

用清晰的语言写下撤销记录：

```text
审查日期：2025-03-07
会话：[会话引用]
原因：SSH 命令超出了批准的维护任务范围
操作：已撤销会话
撤销后的调用：未观察到
相关凭证：已审查，无需轮换
负责人跟进：更新维护运行说明
```

使用实际日期和引用。模板很重要，因为它会迫使审查人说明自己是否检查了撤销后发生的事情。「已撤销」只描述了一个动作，并没有说明结果。

不要把每次撤销都变成纪律处分事件。如果工程师担心停止运行会受到惩罚，他们会一直犹豫，直到能够证明存在恶意意图。撤销的作用是快速停止不确定的操作。后续审查再决定原因究竟是提示词问题、审批错误、凭证设计问题，还是不当行为。

## 轮换从负责人和权限范围开始

需要轮换的凭证应在每周审查中作为等待负责人决定的事项出现，而不是一份恐慌清单。一个凭证应有轮换日期、系统负责人、明确用途和权限范围。缺少其中任何一项，就已经比应有的状态更难管理。

根据审查窗口内使用过的凭证建立一份小型轮换队列。对每个凭证记录负责人、服务、预期用途、下次轮换日期，以及本周活动是否仍符合该用途。开始时不需要复杂的数据库。一份持久保存且标明负责人的记录，比一份无人更新但看起来很完整的清单更有价值。

出现以下任一情况时，应优先轮换：

- 凭证已超过要求的轮换日期。
- 负责人无法解释最近一次使用。
- 凭证权限超过任务需要。
- 凭证曾在访问受到质疑或出现未知进程事件后被使用。
- 团队无法识别负责该服务账户或凭证的人。

没有切换计划的轮换会造成可以避免的中断。替换凭证前，先找出使用它的代理运行、脚本和集成。按照当前任务需要，以最小权限签发替代凭证。测试预期操作，迁移已知使用方，然后停用旧凭证，并确认没有新的活动继续使用它。

不要把「最近没看到它」当作凭证未使用的证明。有些维护任务每月运行一次，或者只在事件期间运行。删除前检查负责人和记录用途。如果两者都不存在，可以在受控时间窗口内禁用它，并观察由此产生的失败。这通常是最快的诚实答案。

还要保留另一个区别：轮换减少密钥的有效使用期限，权限范围则限制密钥能做什么。团队经常试图用频繁轮换来弥补过宽的权限，但这不起作用。新签发的凭证如果访问过多，仍然是访问过多。

## 在解释证据前先验证证据

每周判断是否可靠，取决于背后的记录是否可靠。导出的截图和手工复制的行很方便，但如果有人需要确认它们之后是否被编辑过，这些材料就不是理想证据。

Sallyport 通过一份加密、哈希链式的审计日志记录代理运行和单独调用，同时将它们显示在不同的会话日志和活动日志中。这种分离很有用，因为审查人可以从进程审批记录转到该运行期间的具体调用，而不会把两类记录混为一谈。

在正式开始审查前，或在关注事件后保存证据时，运行可用的离线完整性检查：

```sh
sp audit verify
```

该命令会对密文验证审计链，不需要保险库密钥。验证成功说明按照所记录的哈希，链条保持完整。但它不能证明获授权的人做出了明智审批，不能证明目标合适，也不能证明凭证权限范围合理。完整性和判断是两项不同的工作。

如果验证报告问题，就不要再把相关导出文件当作已经确定的证据。保留文件，记录命令的准确结果，然后调查存储和应用状态。不要为了让报告看起来正常而「清理」记录。在根据日志得出结论前，你需要知道问题来自损坏、复制不完整，还是人为干预。

对于普通每周审查，如果团队需要可辩护的记录，就把验证结果和审查记录放在一起保存。对于低风险的本地实验，也可以选择更轻量的做法，但决定应当明确。要避免的情况是，恰好在包含严重发现的那一周悄悄跳过验证。

## 审查需要固定的 35 分钟节奏

短时审查只有在你为决定预留时间时才有效，而不是在其他工作结束后才说「看看日志」。对于代理运行数量可控的团队，下面的流程已经足够。只有当数量或风险确实需要时，才增加时间。

1. 用五分钟验证审计记录并设置日期范围。打开上次审查记录，让未解决事项保持可见。
2. 用十分钟审查新会话。把每个陌生进程或持续时间异常的运行与负责人和任务对应起来。
3. 用十分钟审查异常成功操作和失败调用。在对任何事件分类前，先调出周边上下文。
4. 用五分钟审查被撤销的会话。检查触发原因、撤销后的活动和明显的并行权限。
5. 用五分钟审查凭证轮换。为每一项需要行动的事项指定负责人和截止日期。

最终只保留一份审查记录，并使用三个标题：发现、决定、待办负责人。发现是观察到的事实。决定说明你要做什么。待办负责人写明必须完成某件事的人。混淆这些类别后，记录里就会充满「监控」和「审查」这样的模糊动词。

下面这种简洁格式通常很实用：

```text
期间：[开始时间] 至 [结束时间]
审查人：[姓名]
审计验证：通过或需要跟进

发现
- [记录引用] [观察到的事件及上下文]

决定
- [已采取的行动及原因]

待办负责人
- [人员] 将在 [日期] 前完成 [具体行动]
```

一次每周审查没有发现问题，也可能是一次好的工作，但要写明检查了什么。「没有问题」无法告诉下一位审查人你是否检查了会话来源、撤销、失败或轮换。几行具体记录能为下周建立基线。

不要因为所有人无法出席就推迟审查。一位了解情况的审查人可以先完成证据检查，之后再把问题分派给负责人。等待所有人都到齐，正是七天流程变成六周空档的原因。

## 记录应当改变访问决定

如果审查只产生一份报告，它就失败了。每个反复出现的发现都应改变以下四项中的至少一项：任务说明、审批边界、凭证权限范围，或自动化本身。

对预期端点反复失败的调用，可能需要修复集成。代理在代码审查期间不断选择部署工作，可能需要更严格的任务说明，并且不应获得部署凭证。反复出现的未知会话，可能需要改变开发者启动代理的方式。反复使用宽权限凭证，则可能说明应按用途拆分凭证。

Sallyport 可以要求新代理进程获得审批，也可以要求每次使用指定凭证时都获得审批。对于需要人类检查每次尝试的操作，应使用第二种控制，而不是试图通过一套庞大规则表达这种判断。

不要对所有地方都增加审批。如果审查人每周都看到同一个无害调用，却无法把它和高风险调用区分开，说明审批设计有问题。应把低风险的重复工作放入边界明确的凭证中，把按次审批保留给那些后果需要人类决定的操作。

保留一份简短清单，记录反复出现的发现及其修复状态。当同一类别连续三次审查都出现时，不要再把它当作孤立观察。有人需要改变运行设计。日志已经告诉你，当前边界与实际工作不匹配。

第一次审查可能会有些尴尬，因为它会暴露缺失的任务引用、没有名称的凭证和不清晰的负责人。这种不适感是有价值的。写下未回答的问题，指定负责人，下周重复同样的流程。目标不是让日志毫无瑕疵，而是建立一个代理环境，让人仍然能够解释谁做了什么、为什么这么做、结果如何，以及哪些访问权限仍然存在。
