第四章:审计日志常见字段概述

咱们做审计日志,第一步得搞清楚一条日志里必须装哪些东西。说白了,日志字段的设计决定了你事后能不能把事故现场还原出来。

我这些年看过太多「字段随意、格式混乱」的日志了。有一次客户说系统被攻击了,我翻了两天日志——时间格式不一致、事件类型乱写、用户字段全是空串。最后只能用Web服务器Access Log凑合着追。这种坑,踩过一次你就知道字段标准化有多重要。

这一章我把最核心的字段挑出来讲:时间、事件类型、用户、来源、结果。这五个是审计日志的「骨架」,缺一个都不行。

审计日志核心字段关系图 审计日志核心字段关系图 审计日志 时间 (Timestamp) 事件类型 用户身份 来源 (Source) 结果 (Result) 说明: • 时间戳必须精确到毫秒,且采用 UTC 或带时区标识的 ISO 8601 格式。 • 事件类型建议使用标准化枚举(如 CRUD、登录/登出、权限变更)。 • 用户身份应包含 UID + 角色/租户,来源包含 IP 和设备指纹。 • 结果字段必须记录操作是否成功及失败原因码。

1. 时间字段(Timestamp)

时间字段是最基础的,也是最容易出错的。我见过有人用本地时间,也不带时区。结果跨地域审计时,时间线全乱套。

标准做法:使用 UTC 时间,格式遵循 ISO 8601。比如 2025-03-20T14:23:45.123Z。

你想想看,如果日志里只写 2025-03-20 14:23:45,你知道这是东八区还是 UTC 吗?一旦系统跨机房部署,时间对齐就直接凉了。

推荐字段结构:

  • timestamp — ISO 8601 字符串,精确到毫秒
  • timezone — 可选,记录原始时区(便于本地化展示)
  • nano_seconds — 高精度场景额外记录纳秒部分(如金融交易)

我的习惯:在服务端生成时间戳,不要依赖客户端时间。客户端时间可以被篡改。我曾经遇到过一台客户机器时间差了两小时,导致日志顺序完全不对,排查花了一整天。

2. 事件类型字段(Event Type)

事件类型决定了这条日志属于什么操作。你得有一套统一的分类体系。别说什么「增删改查」这种粗糙分类。

我个人推荐用两级枚举:大类 + 小类。比如:

  • LOGIN → LOGIN_SUCCESS, LOGIN_FAILURE
  • DATA → DATA_CREATE, DATA_READ, DATA_UPDATE, DATA_DELETE
  • ADMIN → ADMIN_ROLE_CHANGE, ADMIN_CONFIG_MODIFY

为什么不只用 single string?因为你在查询时,你想查「所有登录失败事件」还是「所有数据删除事件」,单字段匹配容易误伤。用组合字段会更灵活。

当心:不要用数字表示事件类型(比如 type=1 表示登录)。可读性太差,运维排查时还得翻映射表。直接存字符串,不要吝啬那点存储空间。

3. 用户身份字段(User Identity)

谁干的?这个字段不能只存一个用户名。现代系统里,用户可能属于不同租户、不同角色。单靠 username 根本无法确定权限范围。

我建议至少包含以下三个子字段:

  1. user_id — 全局唯一用户 ID(UUID 或自增 ID)
  2. username — 用户可读名称(方便显示)
  3. tenant_id — 租户/组织 ID(SaaS 场景必须)

另外,别忘了 session_id 或者 request_id。它们能把同一用户的一次操作串起来,形成审计轨迹。

4. 来源字段(Source)

这个字段记录「操作从哪来」。主要有三个方面:

  • 源 IP 地址:客户端的真实 IP。注意负载均衡环境下要拿 X-Forwarded-For 的头。
  • 源端口:可选,用于 TCP 连接追踪。
  • 用户代理/设备指纹:浏览器 UA、设备型号、操作系统版本。可以用来判断异常登录。

我遇到过一个案例:攻击者使用了 VPN,IP 一直在变,但 UA 始终是同一个老版本 Chrome。最终通过 UA 指纹锁定了同一个人。

小技巧:在来源字段里加一个 geo_city 属地信息,虽然会增加日志体积,但在风控场景下非常有用。不用实时查 IP 库,直接看日志就知道是不是异地登录。

5. 结果字段(Result)

操作成功还是失败?光记一个布尔值不够。还要记录失败原因码和错误描述。

推荐结构:

字段名 类型 说明 示例
result_code 整数 0 表示成功,其他数字表示不同错误类型 0, 401, 403, 500
result_message 字符串 人类可读的错误描述 "User not found"
result_sub_code 字符串 可选,业务自定义错误码 "ERR_PASSWORD_EXPIRED"

为什么要区分 result_code 和 result_sub_code?因为标准 HTTP 状态码(401/403/500)太多人用了,但在审计业务中你可能需要更细的粒度。比如都是 403,你是「权限不足」还是「IP 被拉黑」?子码就能区分。

6. 其他常见字段

除了上面五个核心字段,我还建议加上:

  • object_id:操作的对象 ID(比如删除的文件 ID)。
  • object_type:对象类型(文档、用户、配置项等)。
  • action_detail:额外的描述信息(比如修改了哪些字段,旧值新值)。
  • correlation_id:全局关联 ID,用于追踪跨系统调用链。

这些字段虽然不是每个场景都强制,但它们能极大地提升审计的可用性。你可以根据自己的业务选配。

注意:不要存储敏感数据到日志里,比如密码明文、信用卡号。审计日志通常长期保存,如果泄露就是重大安全事件。我在设计字段时,会在日志输出前做一次脱敏过滤。