4、审计日志字段解析:时间戳提取、源IP/目标IP提取、用户与事件类型识别归纳

字段解析,说白了就是让机器读懂日志。嗯,我刚开始做 Splunk 的时候,拿到原始日志直接搜,结果一堆乱码。后来才明白——字段不解析好,搜索效率、告警准确性全白搭。这一章咱们就把审计日志里最常见的四个核心字段拆开揉碎:时间戳、源 IP、目标 IP、还有用户和事件类型。

4.1 时间戳提取:别让日志"穿越"

时间戳是审计日志的灵魂。我记得有一次排查安全事件,日志时间比实际慢了8小时,差点误判攻击时间。为什么会这样?因为 Splunk 默认用日志到达时间(_indextime),可真正有用的,是日志里那个原始时间。

本质上你要做两件事:告诉 Splunk 时间戳在哪个字段里,以及它的格式是什么。默认 Splunk 自动识别常见格式(比如 ISO 8601),但遇到自研系统或者老设备,你就得上手了。

很常用两种方式:props.conf 里的 TIME_PREFIX / TIME_FORMAT 或 搜索时的 strptime 函数。举个例子,日志长这样:
2025-03-21 14:32:18,452 host=10.0.1.5 action=login user=zhang
在 props.conf 里写:
TIME_PREFIX = ^
TIME_FORMAT = %Y-%m-%d %H:%M:%S,%3N
如果只想在搜索里提取,用:
| eval extracted_time = strptime(raw, "%Y-%m-%d %H:%M:%S,%3N")
| convert ctime(extracted_time)
日志来源典型格式TIME_FORMAT 示例
Linux syslogMar 21 14:32:18%b %d %H:%M:%S
Windows Event Log03/21/2025 14:32:18.452%m/%d/%Y %H:%M:%S.%3N
Nginx access21/Mar/2025:14:32:18 +0800%d/%b/%Y:%H:%M:%S %z
自研微服务 JSON"timestamp": 1711003938452epoch 毫秒 → 用 eval 转换
注意:如果日志里时间戳不含时区,而你的 Splunk 服务器在 UTC,务必在 props.conf 里加上 TZ = Asia/Shanghai。我踩过这个坑,差点被绩效面谈。

4.2 源IP/目标IP提取:从混乱到有序

审计日志里 IP 通常是成对出现的:src_ip 和 dest_ip。但不同设备写的字段名千奇百怪——saddr、sourceAddress、clientip、host……你想想看,如果手写正则匹配每次都不一样,那还怎么自动化?

我的做法分两步:先用字段提取把所有可能的名字统一,再用 eval 做标准化。

4.2.1 搜索时用 rex 或 spath

对于非结构化的文本日志,用 rex 正则拿到 IP:

| rex "from (?<src_ip>\d+\.\d+\.\d+\.\d+) to (?<dest_ip>\d+\.\d+\.\d+\.\d+)"

对于 JSON 格式,直接用 spath:

| spath path=source_ip output=src_ip
| spath path=dest_ip output=dest_ip

4.2.2 用 eval 做归一化

因为字段名乱,我喜欢建一个辅助 sourcetype 级别的字段别名表:

| eval src_ip = coalesce(src_ip, sourceAddress, saddr, clientip)
| eval dest_ip = coalesce(dest_ip, destAddress, daddr, server_ip)

这样不管原始字段叫什么,最终都收口到 src_ip 和 dest_ip。

我在一次跨机房流量审计时就靠这个把 6 种不同设备日志统一了。原来每天人工对 IP,现在一条 SPL 搞定。

4.3 用户与事件类型识别:谁干了什么

审计日志的两个灵魂拷问:谁干的?干了什么事?用户字段常见的有 user, username, uid, account, identity。事件类型更乱——action, operation, event, result 等等。

我一般先把用户字段归一化,再根据事件类型打标签。举个例子,将不同的登陆成功、失败统一成 "login_success" 和 "login_failure":

| eval user = coalesce(user, username, uid, account)
| eval event_type = case(
    action=="LOGIN" AND result=="SUCCESS", "login_success",
    action=="LOGIN" AND result=="FAILED", "login_failure",
    action=="DELETE" OR action=="remove", "delete_operation",
    action=="CREATE" OR action=="add",   "create_operation",
    1==1, "other"
  )

这样不管原始日志写什么,最终都能归纳到可统计的类别里。我在做 UBA(用户行为分析)时,就靠这个 event_type 字段做基线建模,效果立竿见影。

4.4 字段解析全流程梳理

上面几步走下来,其实已经形成了一个完整的提取链路。我把它画成一张图,方便你对照落地。

审计日志字段解析流程 原始日志 时间戳提取 源IP / 目标IP提取 用户 + 事件类型识别 结构化字段集 自动化巡检 / 告警 四步串联:原始日志 → 三路字段解析 → 汇聚结构化 → 驱动自动化巡检

你按这个流程去配置你的 props.conf 和搜索,再复杂的审计日志都能规整。最后把结构化字段丢进告警里,基本就落地了。

提个建议:字段解析的配置,最好写在 props.conf / transforms.conf 里,而不是每次搜索用 rex 现场提取。前者性能高,后者适合临时调查。我一般会把常用sourcetype的解析写进配置,线上巡检直接复用。

4.5 小总结:字段解析的价值在哪

说白了,字段解析就是给原始日志穿上「制服」。时间戳、IP、用户、事件类型这四个字段一旦统一,后面做统计、关联、异常检测就顺利多了。我有一次要排查服务器被暴力破解的源IP,按上面的方法归一化后,一条 | stats count by src_ip user event_type 就锁定了攻击者。嗯,搞定。下次你遇到类似场景,试试这套流程。