4. 日志标准化与格式化:从混乱到有序的第一步
说实话,我刚进安全审计这个领域时,面对的第一道坎就是日志格式。那时候各厂商的设备凑在一起,日志长得五花八门——有的用竖线分隔,有的用逗号,有的干脆是自由文本。你想想看,如果连格式都不统一,告警规则怎么写?分析工具怎么识别?
所以这一章,咱们就聊聊日志标准化。说白了,就是把各路“方言”翻译成统一的“普通话”。
4.1 常见日志格式解析
目前业界主流的标准化日志格式有三种:JSON、CEF 和 LEEF。我建议你至少掌握前两种,第三种了解即可。
4.1.1 JSON 格式
JSON 是目前最通用的格式。它的好处是结构清晰,解析简单,几乎所有现代编程语言都原生支持。
{
"timestamp": "2024-03-15T10:30:00Z",
"src_ip": "192.168.1.100",
"dst_ip": "10.0.0.5",
"action": "BLOCK",
"rule_name": "SQL注入防护",
"severity": 7
}
我个人习惯把 JSON 作为首选输出格式。为什么呢?因为它扩展性好。需要加字段?直接往里塞一个 key-value 就行,不会破坏已有结构。
4.1.2 CEF 格式(Common Event Format)
CEF 是 ArcSight 推广的格式,在传统 SIEM 系统里非常常见。它的样子是这样的:
CEF:0|安全公司|产品名|版本号|事件ID|事件名|严重程度|
src=192.168.1.100 dst=10.0.0.5 act=BLOCK
CEF 的核心是“管道符+键值对”组合。我在项目中遇到过一家银行,他们的旧系统只认 CEF,硬是把 JSON 转成 CEF 才接进去。
4.1.3 LEEF 格式(Log Event Extended Format)
LEEF 是 IBM QRadar 的格式,和 CEF 类似,但语法略有不同:
LEEF:2.0|IBM|QRadar|7.2.0|事件名|严重程度|
src=192.168.1.100 dst=10.0.0.5 act=BLOCK
LEEF 我见得少,主要是在 QRadar 集群里必须用它。如果你不用 QRadar,这个格式可以忽略。
4.1.4 三种格式对比
| 特性 | JSON | CEF | LEEF |
|---|---|---|---|
| 可读性 | 高 | 中 | 中 |
| 解析性能 | 中 | 高 | 高 |
| 扩展性 | 强 | 一般 | 一般 |
| 主流 SIEM 支持 | 全部 | ArcSight、Splunk | QRadar |
| 推荐场景 | 新系统、微服务 | 传统安全设备 | IBM 体系 |
我的建议:新建系统优先用 JSON。如果是和旧设备对接,看看对方支持 CEF 还是 LEEF,尽量往 JSON 转。
4.2 字段映射
格式统一之后,下一步就是字段映射。什么叫字段映射?就是让不同设备里意思一样的字段用同一个名字。
举个例子:
- 防火墙 A 里叫
source_ip - 防火墙 B 里叫
src - 漏扫设备里叫
client_addr
这三个字段实际上都表示“源IP”。不做映射的话,你写规则就要写三遍。做了映射,统一叫 src_ip,一条规则搞定。
我以前在一个 SOC 项目里遇到过一个坑:某厂商的日志里,severity 字段的值范围是 1-5,另一家是 0-100。不映射的话,直接就告警混乱了。
4.2.1 通用字段映射表(建议版本)
| 标准化字段名 | 含义 | 常见别名 | 数据类型 |
|---|---|---|---|
| timestamp | 事件时间 | time、date、@timestamp | ISO8601 字符串 |
| src_ip | 源 IP 地址 | source_ip、src、client_addr | IPv4/IPv6 字符串 |
| dst_ip | 目标 IP 地址 | dest_ip、dst、target_addr | IPv4/IPv6 字符串 |
| src_port | 源端口 | source_port、sport | 整数 (0-65535) |
| dst_port | 目标端口 | dest_port、dport | 整数 (0-65535) |
| action | 处理动作 | act、result、verdict | 枚举 (ALLOW/BLOCK/LOG) |
| severity | 严重程度 | priority、level、event_severity | 整数 (0-10) |
| event_name | 事件名称 | name、event_type、signature | 字符串 |
| log_source | 日志来源设备 | device_name、hostname、source | 字符串 |
| raw_message | 原始日志内容 | message、raw_log | 字符串 |
4.3 标准化规范设计
有了格式和字段映射,还得有一整套规范来约束。不然每人按自己的理解来,最后又是一团乱麻。
我总结了一套“四层规范”的设计方法:
| 层级 | 规范内容 | 示例 |
|---|---|---|
| L1 格式层 | 日志必须使用 JSON | 严禁使用 CSV、自定义分隔符 |
| L2 字段层 | 必选字段必须存在 | timestamp、src_ip、action 不能为空 |
| L3 取值层 | 枚举字段必须用指定值 | action 只能是 ALLOW/BLOCK/LOG |
| L4 命名层 | 字段名采用 snake_case | 用 user_name 不用 userName |
4.3.1 规范设计原则
- 最小完备原则:字段数量够用就行,别什么都往里塞。我记得有个项目,一个日志里塞了 50 多个字段,解析和存储都炸了。
- 向前兼容:新增字段不能改变已有字段的含义。你想想看,如果某天把
severity从“数字越大越严重”改成“数字越小越严重”,那之前的规则全得重写。 - 统一时间格式:时间戳必须用 ISO8601,带时区。我以前见过用 Unix 时间戳、用 yyyyMMdd 格式的,解析时头都大了。
- 避免特殊字符:字段名和值里不要出现换行符、制表符、双引号。JSON 里虽然能转义,但你手动查日志时会疯掉。
4.3.2 避坑指南
我曾经接手过一个项目,日志标准化规范都写好了,但落地时发现有些老设备根本改不了格式。后来想了个折中方案:在采集端加一层“日志转换器”,用 Logstash 或 Fluentd 把老格式转成标准 JSON。这个思路你也可以参考。
4.4 本章知识体系
下面这张图梳理了日志标准化与格式化的核心逻辑:从原始日志输入,经过格式识别和字段映射,最终输出标准化的日志对象,供后续告警流程使用。
标准化这件事,做好了不容易察觉,做不好处处是坑。但它又是整个告警流程优化的地基——地基不牢,上层的规则再精巧也白搭。我自己踩过的坑,希望你能绕着走。