3.5 审计与取证

一句话

审计要能回答 “谁、在什么时候、对什么、做了什么、结果如何”,且日志不可篡改;取证是 “把这五要素变成可呈交的证据链”——没有时间源、完整性与访问记录,日志只是一堆文本。

审计日志的五个要素

要素 内容 常见缺失
Who 主体(账号、IP、设备、服务身份) 只记 IP,不记账号/租户
When 时间(统一时间源、时区) 各服务时钟不同、时区混乱
What 对象(资源 ID、字段变更前后) 只记 “更新了” 不记改了什么
Action 操作(读/写/删/导出/授权) 不区分 “查看” 与 “导出”
Result 成功/失败/拒绝原因 只记成功,失败尝试丢失

保留期与不可篡改

项 常见要求 实现
留存期 等保常要求 ≥6 个月;行业有更长要求 分层存储(热 30 天 / 冷 6 个月+)
不可篡改 只追加、可验证 WORM 存储、对象锁、哈希链
访问控制 只有审计员可读,运维不可删 独立账号 + 最小权限 + 操作审计
完整性 能证明 “未被改过” 每条日志带前一条哈希(哈希链)

代码:带哈希链的审计事件

// 每条审计事件把“上一条的哈希”串进来,篡改一条就会断链
type AuditEvent struct {
    Seq      uint64    `json:"seq"`
    Time     time.Time `json:"time"`      // 统一 NTP/PTP 时间源
    Actor    string    `json:"actor"`     // 账号/服务身份
    Tenant   string    `json:"tenant"`
    Action   string    `json:"action"`    // read/export/delete/grant
    Resource string    `json:"resource"`
    Before   string    `json:"before,omitempty"`
    After    string    `json:"after,omitempty"`
    Result   string    `json:"result"`
    PrevHash string    `json:"prev_hash"`
    Hash     string    `json:"hash"`      // sha256(前 12 个字段 + PrevHash)
}
# 验证日志链是否连续(简化:逐条比对 prev_hash)
jq -r '[.seq,.prev_hash,.hash]|@tsv' audit.ndjson | \
  awk 'NR>1 && $2!=prev {print "断链 at seq",$1} {prev=$3}'

反模式

反模式 后果
审计日志与业务日志混在一起 被轮转清掉、被业务查询淹没
运维账号能删审计日志 内部人可抹痕迹,审计失效
只记 “成功”,不记失败/拒绝 无法发现暴力破解、越权尝试
不记 “导出了什么” 大规模泄露无法定位范围
时间源不统一 跨服务无法还原事件顺序
留存期不足 事后调查时日志已过期

三条铁律

🔑 审计日志要独立存储、只追加、不可删。

🔑 失败与拒绝同样要记;攻击往往藏在失败里。

🔑 时间源统一;否则 “谁先谁后” 说不清。

自检

Q1 为什么审计日志不能和业务日志放一起?

▸ 答案:因为业务日志会按容量轮转/采样/被业务方清理,审计日志需要 “完整、长期、不可删”。混在一起通常导致 “出事时关键记录已被轮转掉”。审计要独立通道、独立存储、独立权限。

Q2 为什么 “失败的操作” 也要审计?

▸ 答案:因为攻击与内部风险常表现为大量失败:暴力破解、越权尝试、扫描、误配置。只记成功会漏掉这些信号;失败日志还能证明 “系统确实拒绝了”,在取证时同样重要。

Q3 哈希链能防什么、不能防什么?

▸ 答案:能防事后篡改(改一条就断链,可被发现);不能防 “从一开始就不记”(漏记无法通过哈希发现)。所以还需要 “记录完整性监控”(如关键操作必须产生审计事件,缺失即告警)。

Q4 时间源为什么是取证的关键?

▸ 答案:因为取证要还原 “事件顺序”:谁先登录、谁先导出、谁后删除。各服务时钟漂移会让顺序颠倒,甚至出现 “删除早于创建” 的荒谬结论。统一 NTP/PTP 并记录时区,是取证可信的前提(见 23.1 物理时钟与漂移)。

Q5 取证时 “证据链” 指什么?

▸ 答案:指 证据的获取、传输、存储、访问都有记录且可验证:谁在什么时候导出了什么、哈希是多少、存到哪里、谁看过。缺任一环,证据的 “未被篡改” 就无法证明,可能在调查/诉讼中不被采信。

Q6 审计日志里能不能放明文个人信息?

▸ 答案:尽量不放:审计需要的是 “谁对哪个资源做了什么”,通常用资源 ID + 字段名即可,不必记录字段值。确需记录值时(如金额变更),要做脱敏/加密与访问控制,避免审计系统变成最大的泄露源。

Q7 怎么验证 “审计真的可用”?

▸ 答案:做一次演练:给定一个场景(如 “某账号导出了 10 万条用户数据”),要求团队在限定时间内回答 “谁、何时、导出了哪些、是否成功、日志是否完整”。答不出来,说明审计只是 “有日志”,不是 “可取证”。

关联