审计日志基础:日志规范、等级、格式

审计日志这东西,说白了就是给系统装个黑匣子。我当年刚接手一个金融交易系统时,日志格式五花八门,有的记在文本文件里分隔符用竖线,有的直接往数据库里怼 JSON 字符串,连个时间戳都是本地时间。等出了安全事件要追溯,那叫一个痛苦。所以咱们得把基础打牢——规范、等级、格式,这三样定了,后续链路追踪才不是空中楼阁。

日志规范:不立规矩不成方圆

你想想看,如果每个微服务团队都按自己喜好写日志,那汇聚到中央的日志就是一团乱麻。我一般在项目启动阶段就定一条硬规矩:所有审计日志必须包含四要素——时间、主体、客体、动作。

  • 时间:统一使用 ISO 8601 格式,带时区偏移。比如 2025-03-20T14:30:00+08:00。别用毫秒时间戳,解析起来坑太多。
  • 主体:谁做的?用户 ID、会话 ID、甚至客户端 IP 都得有。
  • 客体:对什么做的?资源 URI、数据库表名、文件路径。
  • 动作:做了什么?CREATE、READ、UPDATE、DELETE,或者自定义动作如 LOGIN、EXPORT。

核心原则:每条日志必须是能独立证明“某人在某时对某资源做了某事”的最小原子单位。别依赖上下文日志来补齐信息。

除此之外,我还会加一条:所有审计日志必须加密传输。我在一个客户现场见过明文日志在 Kafka 里随便拉,内部人员直接 tcpdump 就能扒出用户行为——这已经不是规范问题,是合规问题了。

日志等级:别把预警和凑热闹混在一起

传统的日志等级(DEBUG、INFO、WARN、ERROR、FATAL)在审计场景里其实不太够用。比如“用户修改密码”这个操作,你该打 INFO 还是 WARN?我觉得还是不够精确。

等级 含义 审计场景示例
DEBUG 调试信息,生产环境一般不记录 一般不用于审计日志
INFO 正常业务流程记录 用户登录成功、查看报表、导出文件
WARNING 异常但不阻断 连续失败登录、访问敏感资源未授权
ERROR 操作失败,业务受影响 转账失败、数据写入失败
CRITICAL 严重安全事件 越权访问、SQL 注入尝试、数据泄露告警

嗯,这里要注意:审计日志的等级不是给开发看栈追踪的,它是给安全分析师做筛选用的。我见过很多团队把所有的用户操作全打成 INFO,然后 CRITICAL 级别反而空着。结果告警系统一查,一个超高危的越权操作跟普通浏览日志混在一起,根本没人当回事。

我的经验:建议每个项目在代码上线前,拉出所有审计日志打点,逐个确认等级是否正确。我曾经因为一个“删除用户”操作打成了 DEBUG 等级(代码里写错了),导致安全审计报告里漏掉了 200 多条非法删除记录——后来追查了整整两周。

日志格式:JSON、CEF 以及其他选择

格式这东西,选对了事半功倍。主流的审计日志格式就两种:JSON 和 CEF(Common Event Format)。

JSON 格式

全名 JavaScript Object Notation。它灵活、可读性强,几乎所有日志收集工具都支持。我个人的偏好是用 结构化 JSON,嵌套层级不超过两层。为什么?解析性能好,Elasticsearch 这类检索引擎处理扁平结构更快。

{
  "timestamp": "2025-03-20T14:30:00.123+08:00",
  "level": "WARNING",
  "audit": {
    "subject": "user_12345",
    "session": "abcd-efgh-ijkl",
    "source_ip": "192.168.1.100",
    "object": "api/v2/accounts/67890",
    "action": "GET",
    "result": "FORBIDDEN",
    "reason": "IP not in whitelist"
  },
  "source": "payment-service",
  "trace_id": "trc_xxxxxxxxxxxx"
}

你看,这个 JSON 包含了完整的链路追踪 ID(trace_id)、source 标识,以及审计核心字段。我在实践中往往会再补一个 tags 数组,用于标注安全等级或合规分类。

CEF 格式

全名 Common Event Format,由 ArcSight 推广。它由竖线分隔的字段组成,头字段固定长度,扩展字段用键值对。很多 SIEM(安全信息与事件管理)系统原生支持 CEF。

CEF:0|MyCompany|PaymentService|1.0|100|Unauthorized access attempt|Warning| src=192.168.1.100 suser=user_12345 target=/api/v2/accounts/67890 cs1Label=session cs1=abcd-efgh-ijkl

CEF 的优点是解析速度极快,但它牺牲了可读性。我在集成自研系统时一般选 JSON,与外部 SIEM 对接时才会转成 CEF。

避坑:我见过有些团队把 CEF 和 JSON 混着写进同一个日志文件,结果解析器直接崩溃。要么全用 JSON,要么全用 CEF,中间件可以做格式转换,但不建议一个源出两种格式。

推荐格式对比

特性 JSON CEF
可读性 高,带缩进和括号 低,全靠竖线分割
解析性能 中等(需完整解析 JSON 树) 高(固定字段可快速定位)
灵活性 强,可自由嵌套扩展 弱,扩展字段有命名约束
工具支持 几乎所有分析平台 主要 SIEM 平台(Splunk、ArcSight、QRadar)
推荐场景 内部系统、自建平台 对接合规审计系统、SOC 场景

知识结构一览

下面这张图把本章核心逻辑串起来了。从规范出发,落到等级和格式,最后生成可审计的日志记录——每一层都不能省。

审计日志基础框架 日志规范(四要素) 日志等级 日志格式 INFO WARNING ERROR/CRITICAL JSON 格式 CEF 格式 可审计日志记录

实战小贴士:从规范到落地的几个习惯

  • 统一时间基准:所有服务必须用 NTP 同步,偏差超过 100ms 的日志直接丢弃。我曾经在微服务集群里发现两台机器差了 3 秒,导致时间线错乱,根本没法追踪。
  • 日志轮转策略:审计日志不能按大小轮转就删掉,必须以天为单位保留,并且至少要留 180 天。合规要求一般是 1 年,金融系统甚至要到 7 年。
  • 敏感字段脱敏:在写日志前就把密码、身份证、信用卡号替换成 ***。很多事故都是日志里明文暴露了用户信息。
  • 使用结构化日志库:比如 logrus、zap(Go)、logback(Java),它们会帮你自动附加时间戳、调用栈、机器名。不要自己手拼字符串。

别忽视日志污染:我前公司有个系统把心跳检测也写进了审计日志,结果每天产生 2 亿条无意义记录,把存储和解析链路全部打满。审计日志只记录与业务或安全相关的事件,网络探活交给监控系统。

总之,审计日志这事,看起来是代码里加几行 print,但真正拉开差距的是规范意识。你按 JSON 格式打,配合明确的等级划分,再辅以链路 trace_id,后续的链路追踪和分析才能丝滑。别等出了事再来补日志,那味道就变了。