安全日志搜集与标准化
在一些安全系统中,需要将各种安全设备的日志搜集上来后,再进行标准化以便进行分析。
在设计这类系统时,有以下知识与经验可以借鉴。
保留原始日志#
在日志中通过一个字段(比如:“rawEvent”)来存储原始的日志内容,有助于回溯原始的日志内容,帮助发现日志处理过程中有哪些问题。
必要时也可以通过这个字段恢复原始日志并重新进行日志处理,当然如果系统中有 Hadoop 或 Kafka 长期存留日志的话也可以达到同样的效果。
在日志处理过程中增加处理器的标识#
在日志的处理过程中可能会经过:生成,转发,搜集,解析,入库,归并等过程,在每个处理过程中增加本过程的标识,可以方便发现问题。
每个处理过程至少都应该增加开始处理的时间,这样可以方便的统计各个过程的时间消耗。
通过增加过程标识(例如:探针ID,搜集器ID,解析规则ID等),可以清楚的看出来整个日志的流转过程。
日志解析#
如何对日志进行解析?第一个想到的可能是正则表达式,如果日志有很多字段,捕获这些字段的正则表达式则会比较繁琐, 如果再加上对每个字段的校验的话,解析一条日志的正则表达式将会非常难以阅读和维护。
Grok 是一个可以简化这一过程的工具,可以将其理解为正则表达式的宏。例如解析一个ipv4的字段并存储在变量中,正则的写法是:
(?<ClientIp>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)
用 Grok 的写法是:
%{IPv4:ClientIp}
由于 Grok 内置了常见字段的解析,所以编写时只要使用就可以了。
例如要解析下面的日志:
55.3.244.1 GET /index.html 15824 0.043
可以使用下面的写法:
%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}
具体的介绍可以参考:
https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html#plugins-filters-grok
https://logz.io/blog/logstash-grok/
日志标准化#
如果要将不同的安全设备日志放到一起进行分析,则需要对日志进行标准化处理,使其字段都统一成一个标准。
若是没有丰富的安全设备日志处理经验,很可能无法设计出一套合理的标准化字段,想办法站在巨人的肩膀上则可以规避很多坑。
目前我看到有两种公开的日志标准化方案:
CEF (Common Event Format)#
该标准由 ArcSight 提出,算是一个在国外被广泛使用的标准,奇怪的是关于标准的说明很难找,我只找到下面两个地址:
https://raffy.ch/blog/wp-content/uploads/2007/06/CEF.pdf
CEF标准规定了简单的几个必要的字段以及不少扩展字段,其字段的 key name 是为了传输时简化而缩写的,在日志解析入库后还是应该考虑使用字段的 full name 。
其字段以扁平化的列表形式定义,字段中主要有几个分类:device,source,destination,file,oldFile,request 。
其中的 source 和 destination 是一个泛化的概念,例如在网络时间中可能会有:sourceAddress,sourcePort,destinationAddress,destinationPort 字段, 而在主机的事件中,可能会有:sourceProcessId,sourceProcessName,destinationProcessId,destinationProcessName 字段。
如果事件中只涉及一个进程,使用 source 还是 destination 就要靠实现者酌情处理了。
但在文件信息上,其由使用了 file 和 oldFile 两个分类,给人的感觉有点不一致。
CEF 解析后表示一个五元组的示例:
{
"sourceAddress": "10.42.42.42",
"sourcePort": 38842
"destinationAddress": "10.42.42.1",
"destinationPort": 443,
"transportProtocol": "TCP"
}
ECS (Elastic Common Schema)#
由 Elastic 开发的用于在 Elasticsearch 中标准化的存储事件数据的规范:
https://www.elastic.co/guide/en/ecs/8.7/ecs-reference.html
与 CEF 最大的不同是 ECS 对各种对象都进行了定义,而且使用了嵌套的结构来表达关联的信息。
例如 ECS 定义了 process 对象的字段,而 process.parent 可以是另一个 process 对象来描述其父进程的信息。
ECS 表示一个五元组的示例:
{
"source": {
"address": "10.42.42.42",
"ip": "10.42.42.42",
"port": 38842
},
"destination": {
"address": "10.42.42.1",
"ip": "10.42.42.1",
"port": 443
},
"network": {
"transport": "tcp"
}
}