☰
事件图谱:将离散告警转化为可追溯的攻击链
2026/10/21 5:23:24 网站建设 项目流程

1. 为什么是“事件图谱”而不是又一个告警列表

1.1 一线告警疲劳与情报研判之间的“断链”

做威胁分析和安全运营的朋友应该都有这种感觉:每天打开告警平台,几十上百条告警摆在面前,每条单独看都像那么回事,可你永远说不清“今天这批告警和上周那批到底有没有关系”。告警工单一批批闭环,攻击者却可能已经在你边界上待了半个月,每天挪一点点。

我一开始也是这么干的。先看单条告警的IOC,查一下信誉,命中就封禁,没命中就挂起。时间久了发现一个问题:单条告警能提供的上下文极其有限,而威胁情报的价值恰恰不在那一个孤立的IP或域名上,而在它背后的攻击链——谁在什么时候用什么手法打到了哪个资产上,这个资产后来有没有被用作跳板再去打别人。

传统的告警列表只有时间、来源、目标、类型这几个字段,它天然是扁平的,存不下路径。你没法顺着一条告警去问:这个源IP之前还访问过哪台机器?它和另一个告警里的域名是不是同一批基础设施?要回答这类问题,每查一次就要写一次关联查询,查完还得自己脑补上下文。所谓情报链路,在这套工作方式下根本是断的。

1.2 图谱建模的核心优势:把离散事件变成路径

MiroFish这个名字,最初就是内部对“把情报链路做成一张可以走通的地图”这个想法的代号。事件图谱做的事情很简单:把所有威胁相关的事实——谁、在什么时间、对什么资产、做了什么事、产生了什么结果——以点和边的方式存下来,而不是以一行行的告警记录存下来。

点和边的表达方式有一个很直接的好处:路径可以被遍历。单条告警进去只是一条边,但当数据积累到一定量级,告警和告警之间会自然长出关联。一台服务器先被某IP扫描,几天后被另一个IP利用漏洞拿下了,再过了两天,这台服务器开始向外发起大量异常连接——这三条本来看似独立的告警,在图里就是一条可以回溯的路径。

这个差异不是锦上添花,而是根本性的。传统关系库也能存实体和关系,但多跳查询的性能会随深度急剧恶化。图模型的优势在于多跳遍历是存储结构本身擅长的操作,分析人员不用预先知道要查什么,可以先从一个可疑节点出发,一层层往外走,走的过程中才逐渐形成研判结论。这正是威胁分析最需要的交互方式。

我见过不少团队试图用Excel或SQL把这类关联做出来,最后都瘫在“关联规则写不过来”这件事上。攻击路径千变万化,硬编码规则永远追不上变化的速度,但图模型是数据结构层面的通用表达,它不针对某一种攻击手法,而是对所有“实体-行为-实体”的描述都适用。

2. MiroFish的边界与定位:不做什么,比做什么更重要

2.1 三条主线和两个解耦点

任何项目立项时都要想清楚边界,MiroFish也不例外。我们当时定了三条不能跨越的主线:

第一,MiroFish只做事件关联和情报链路构建,不替代检测引擎。告警的产生还是交给已有的检测规则和流量分析系统,MiroFish只负责接收它们的输出,再在更高一层做关联。

第二,MiroFish做的是辅助研判,不追求全自动化处置。图模型可以告诉分析师“这两条告警大概率相关”,但最终是否封禁、是否隔离,仍然由人来做决定。把自动化程度压在这个位置,既避免了一误报就误杀的尴尬,也让系统更容易被运营团队接受。

第三,MiroFish的输入是研判层数据,不直接碰原始流量和原始日志。这样做一方面是为了性能,另一方面也是职责边界——原始数据的清洗和存储已经有专门的管线,MiroFish只需要吃清洗后的结构化事件。

两个解耦点也很关键。第一个解耦点是存储与分析的解耦:图数据存储和上层检索接口分离,后续换引擎不需要重写业务层。第二个解耦点是实体归一与关系构建解耦:实体抽取与ID映射做成独立模块,因为它往往是整个链路里最不稳定、最需要反复迭代的部分,把它独立出来能避免拖垮下游。

2.2 明确什么数据源会被纳入“情报链路”

项目早期最容易犯的错误是恨不得把所有数据都接进来。我们踩过这个坑,后来收敛得很痛苦,所以必须先说清楚——MiroFish只在以下三类数据源上工作:

第一类是安全设备告警,包括防火墙、入侵检测系统、终端检测响应系统的告警输出。这些数据是最直接的线索来源,缺点是噪声大、质量参差。

第二类是威胁情报订阅,包括公开的IOC情报、恶意样本分析报告、漏洞通告等。这类数据用来给图谱“补背景”,比如一个未知IP之所以可疑,是因为它在某份情报里被标注为某个攻击组织的C2基础设施。

第三类是内部的资产台账和漏洞扫描结果。没有资产信息,很多告警关联根本做不起来,因为你看不出被攻击的目标重要不重要、是不是已过保的陈旧系统。

这三类数据的共同点是:都已经是结构化的、带有明确时间戳的、可以被归一到有限类型集合的数据。日志全文、PCAP包这类原始数据不在范围内。划清楚这条线之后,整个项目的数据处理逻辑才真正收敛下来,后续做实体抽取、关系构建时也没有因此返工。

3. 事件图谱的数据建模:实体、事件、关系三层如何设计

3.1 实体层:攻击者、资产与受害者的身份归一

MiroFish的实体类型从一开始就控制在很小的集合里,只有四类:攻击者主体(IP、域名、文件哈希)、资产节点(主机、服务器、业务系统)、人员账号(内网账号、邮箱)、工具与漏洞(漏洞编号、恶意软件家族)。

这个设计是刻意做薄的。很多图谱项目喜欢把实体类型定义得特别细,什么“钓鱼邮件”“恶意附件”“受控主机”全当成不同实体,结果类型之间交叉关联多到没法维护。我们的原则是:实体只承担“是谁”的职责,“发生了什么事”一律丢给事件节点。

实体层的核心难题是身份归一。同一个攻击者IP可能在不同报告里出现两种写法,同一台受害主机在不同告警系统里可能是不同的主机名。MiroFish在实体层做了一个独立的ID映射服务,外部来的每一个实体都会先走一遍标准化和归一,匹配上已有的实体就复用ID,匹配不上才新建。ID一旦确定,原则上不允许变更,这为后续图谱长期积累打下了基础。

3.2 事件层:从告警到“原子事件”的抽象

实体本身不会讲故事,真正承载信息的是事件节点。MiroFish里的事件不是直接拿告警原文当节点,而是先做了一次抽象,把它变成“某个时间、某个主体、对某个对象、做了某个动作”的四元组结构。

比如一条原始的设备的告警原文可能是:“检测到来自IP 203.0.113.5的HTTP请求中包含某漏洞利用特征,目标为10.0.0.8的Web服务端口。”抽象成原子事件就是:源实体[IP 203.0.113.5] —发起利用行为→ 目标实体[主机10.0.0.8]。这条抽象结果本身是一件事,不再掺杂设备厂商的产品术语。

把事件从告警中抽象出来有一个非常实际的好处:同一件事可能被多个安全设备同时上报,传统方案会收到三条重复告警,而MiroFish的事件合并机制会让它们指向同一个事件节点。事件层因此天然有了去重能力,而且这个去重发生在图谱构建阶段,比告警平台上去重更彻底。

事件节点上保留几个关键属性:发生时间、发现时间、置信度、信息来源、原始告警ID。保留原始告警ID是为了让分析师可以从图谱节点一键跳回原始告警平台核对原文,不能为了图结构的清爽丢掉溯源能力。

3.3 关系层:时序性、方向性与置信度

关系是图谱的灵魂,但关系不能乱建。我们定义了六种基础关系类型:访问、扫描、利用、投递、回连、横向移动。所有告警和情报在转换为事件时,最终都落到这六种关系之一。多做一种关系类型就要多维护一条规则链,这在初版阶段是纯粹的负担。

时序性通过边上的开始时间、结束时间和持续时间来表达。一条事件边如果只有“发生时间”而没有“持续时间”,那么它在时间线上的聚合能力就很弱,比如一次持续数小时的扫描行为和一次几毫秒的单包探测,在图里的形状完全不一样。

方向性不用多说,但容易忽略的是置信度。MiroFish在每条关系边上都维护一个0到1的置信度值,这个值不是拍脑袋给的,而是由几个因素综合计算出来的:数据源的可信等级、事件命中的检测规则强度、实体归一过程的确定性。置信度在后续路径回溯时用来排序,高置信路径优先展示,低置信路径折叠显示,避免分析师被噪声路径淹没。

这张三层模型跑通之后,MiroFish的数据骨架基本稳定,后面所有问题都变成了工程问题。

4. 打通情报链路的四个关键工程环节

4.1 数据接入与标准化:先解决格式战争

MiroFish面对的每一个数据源格式都不一样,这是所有安全数据项目躲不开的第一道坎。有的数据源是JSON格式的API输出,有的是CSV报表,有的干脆就是邮件里的人工通知。接入层做了一个统一的标准事件模型,不管上游是什么格式,进入MiroFish之前都必须转换成标准JSON事件。

标准化工作不是字段名映射那么简单,真正的编译工作发生在时间解析和IP/域名的格式归一上。不同设备的时间戳格式五花八门,有的带时区有的不带,有的精确到毫秒有的只能到分钟。我们统一规定:内部一律使用ISO 8601带时区格式,入库前全部转成UTC存储,展示层再做本地时区转换。

这套标准化管线跑了两周才把主力数据源全部接完。过程不复杂,但极其琐碎——每个数据源都要单独写一套转换逻辑,还要处理字段缺失、字段类型不一致这些老问题。建议后来者早点把这一层抽象出来,不要边接数据边写转换,不然清洗逻辑会散落到各处,之后想改一个时间字段的解析规则得翻遍所有代码。

4.2 实体抽取与ID映射:决定图谱质量的胜负手

接收标准化事件之后,第一步是抽取出事件里的实体。这个环节看似简单,但被无数细节折磨过才知道痛。

举个最常见的例子:一条告警里的源IP字段,有的数据源给的是IP地址,有的给的是内网主机名,有的给的是域名。对象字段更乱,同一个IP在不同数据源里可能是“目标IP”“受害资产”“对象域名”,名称不同但指向同一个东西。实体抽取模块要做的就是把所有这些字段统一收敛到实体层的四类实体上,并同步完成ID映射。

我们为这套映射设计了一个多层匹配策略:精确匹配优先(IP地址、域名逐字匹配),其次是有损标准化匹配(去掉端口、去掉协议前缀后再比),最后才是模糊匹配(借助已有情报里的别名关系)。匹配过程中每一步都会更新置信度,匹配不上的实体也不急着新建ID,而是先放进一个待确认缓冲队列,等更多证据出现再最终确定。

ID映射是图谱长期积累的命根子。一旦同一个实体被分到两个ID,后面所有图计算都会产生虚假分裂;反过来,如果两个不同实体被错误合并成一个ID,那会造成更致命的虚假关联。我们在这个模块上花掉了整个项目三分之一的开发工时,现在回头看,这笔投资完全值回票价。

4.3 关系构建与事件链合并:把“点事件”连成“线路径”

实体抽取完成之后,每个事件节点就知道自己牵涉到哪几个实体了。关系构建模块负责在事件与实体之间建立边。这一步的逻辑相对直接:按事件类型确定关系方向,从源实体指向目标实体,然后在边记录上带着时间窗口和置信度。

关系构建之后是做事件链合并。合并规则设计成可配置的,核心思想是:如果两个事件节点中间有共同的实体、时间窗口有重叠、且事件类型之间能够构成逻辑上的下一步(比如“扫描”后面跟“利用”是合理演进,“利用”后面直接跟“横向移动”也是合理演进),那么就在它们之间建立“演进”类型的边。

这套事件链合并规则是最需要业务经验沉淀的地方。我们一开始只处理最简单的时序关系,后来发现大量真实攻击中,攻击者会在两个阶段之间停顿很久,有的长达数日。于是引入了一个关键参数:最大允许时间间隔。超过这个间隔的两个事件不认为构成同一条攻击链,宁可断开也不能硬连。这个参数在项目里被反复调了很多轮,最终定在一个经过验证的保守值上。

4.4 图存储选型与查询设计:跑得动才是硬道理

MiroFish的存储层一开始就是按图数据库来选型的。对比过关系库加图查询中间层和原生图存储两类方案,最终选了原生图存储,因为多跳查询的性能差距实在太明显。在关系库里做三跳以上的关联查询,需要不停JOIN,数据量上来后延迟指数级增长;原生图存储做同样的事,延迟基本只跟遍历的节点数成正比。

存储设计上有两个细节值得提。一是边方向索引,库里同时建了出边和入边两套索引,反向回溯在威胁分析里和正向追踪一样常用,比如你想知道“这台服务器曾经被多少外部IP访问过”就需要入边快速查询。二是属性索引只建在实体节点和事件节点的关键过滤属性上,不要对所有属性都建索引,否则写放大和存储膨胀会拖垮性能。

检索接口我们封装了一层图查询服务,对外只暴露有限的几个查询能力:按实体查询周边一级关系、按时间范围查询事件序列、按路径模板查询攻击链、按相似度查询相似子图。把查询能力收窄到这几个,一方面是为了快速开发,另一方面也是防止分析师写太复杂的图查询,最终跑出一堆不归路。

5. 实测中踩过的坑:ID漂移、共指消解与图谱膨胀

5.1 ID漂移问题:一个域名,两种写法

第一个大坑是ID漂移。上线第三天就发现,某台受害主机在设备告警里以IP形式出现,在资产台账里却是主机名形式,入库后被打成了两个实体ID。结果就是明明指向同一台机器的告警,在图里却分成了两条不相关的路径。

排查发现根因在于实体映射规则里没有覆盖“IP与主机名的对应关系”。完整修复需要引入一张资产别名表,定时从资产台账同步“IP-主机名”的映射关系,实体匹配时先查别名表再做匹配。之前设计的所谓多层匹配策略,精确匹配和标准化匹配都覆盖不到这种跨类型对应。

这个问题的教训是:实体的身份归一不能只靠单条数据本身的字段,它必须依赖外部数据源提供跨字段的别名关系。建议在处理任何安全数据时,先问一遍:这个数据源有没有提供实体之间的等价关系?如果有,尽早接入,不要等到图谱已经长出来再清数据。

5.2 共指消解:同一组织在不同情报里的不同名字

第二个坑来自情报源之间的冲突。某个情报源把一组恶意域名标注为某攻击组织的基础设施,另一个情报源则把这组域名标注为另一个攻击组织。两个组织名在图里指向不同的实体,实际的攻击基础设施却被切成了两块。

我们一开始的做法是直接拉一条“别名”边把两个组织实体连起来,后来发现这么做会在实体上形成螺旋状纠缠,查询时经常跑到不相关的子图上。最终改成在组织实体上增加一个别名列表属性,由人工研判确认后才写入,宁可慢一点也要确保共指消解正确。

这里是整个项目里最需要人工介入的环节。自动化批量合并同类情报实体在前期能省事,但一旦合并错误,被污染的边证据会误导所有后续研判,清理成本比人工逐一确认高一个数量级。我们的结论是:让机器做候选,让人做最终决定。

5.3 图谱膨胀与过期事件治理

第三个坑已经属于“幸福的烦恼”了——数据跑了一个月后,图谱膨胀到几百万个事件节点,查询明显变慢,连带着图数据库的备份恢复时间都变得不可接受。

膨胀的根源有两类。一类是真数据增长,这个没办法,只能靠扩容解决;另一类是无效节点堆积。安全设备每天产生大量低价值告警,扫描探测、误报、重复事件,这些在图谱里白占大量节点和边。

治理方案是引入时间衰减和置信度门限双机制。时间衰减指的是超过一定时限的事件节点,如果没有连接任何高置信度攻击链,就定期归档到冷存储,不再参与在线图查询。置信度门限则针对低置信度事件,那些置信度低于阈值的单点事件不直接进主图,先进分期批量再评估。这两个机制上线后,主图规模下降了一半多,在线查询性能立即恢复到可接受水平。

这套治理策略也要求实体层单独做长期保留。资产的实体信息是图谱长期价值的所在,不能被归档事件顺手清掉。事件可以冷热分离,实体始终要保持在热存储里,毕竟所有新事件都是关联到实体上的。

6. 把图谱交给一线分析师:查询能力与研判工作流的配合

6.1 典型研判路径:从单条告警到路径回溯

MiroFish不是给安全研究员做学术分析的,它的直接用户是SOC一线分析师,应用场景是日常告警研判。部署后我们和运营团队一起把基础研判流程梳理出了一条典型路径。

分析师在告警平台看到一条可疑告警以后,如果这条告警已经同步到MiroFish,就可以在图谱界面里点开对应的实体节点。默认视图只展示这个实体周围一层的关系,先看它近期连接过哪些其他实体。如果一层视图里出现异常实体,分析师可以沿着异常方向继续展开第二层、第三层。

第三层往往是关键所在。举例来说,一条告警的内网主机节点向外连接了一个外部IP,展开后发现这个外部IP在一份早期威胁情报里,已经被标注为某个组织的基础设施;再展开一层,发现该外部IP还为另外三台内网主机提供过服务。这三台主机里有一台是老漏洞系统,另一台是高权限运维跳板机。到这里,研判结论已经很清晰了,不需要分析师再人工拼凑上下文。

这条研判路径的实际操作时间通常不超过十分钟。放在以前,同样的结论需要分析师手工查三四个系统才能拼出来,还不一定敢下结论。这正是事件图谱这个项目最让我觉得值的地方。

6.2 与外部威胁情报源的衔接与可信度标注

MiroFish早期接入的外部情报源以开源情报为主,也有一部分商业化数据服务。外部情报本身质量参差,有的更新及时且准确,有的信息已经过期半年。因此,MiroFish不为情报源做“一刀切”的信誉判断,而是在情报节点上记录来源、发布时间、信誉分三个属性。

来源属性记录这条情报是哪个数据源提供的,便于后续追溯“这个关联结论依据的原始情报是什么”。发布时间用于判断时效性,一条超过三个月的情报即使还在图谱里,展示时也会显著弱化。信誉分则是为每个数据源设置的基础权重,它决定了从该源进入图谱的边的默认置信度基准值。

外部情报触发的事件链合并在默认情况下不会直接和内部告警事件融合显示,而是用虚线区分。分析师可以一眼看出哪些关联是基于内部证据实锤的,哪些是外部情报推测的。这个设计大幅减少了“外部情报带偏内部研判”的情况。很多安全事件误判往往不在于内部数据错了,而在于外部情报里掺杂了太多需要消化的噪声。

7. 效果评估与后续演进

7.1 我们用哪三类指标衡量“打通程度”

项目上线三个月后,团队复盘时设计了三类指标来回答“我们到底打通了没有”这个问题。

第一类是关联覆盖率:进入MiroFish的全部告警事件中,有多少比例的实体节点至少存在一条有效关系边,而不是孤立节点。孤立节点意味着这条数据虽然入库了,但还没有参与到任何情报链路里。这个指标在存量数据清洗和增量接入两个维度上分开统计,目标是让孤立事件占比控制在20%以下。

第二类是攻击链识别率:在已成链的事件组合中,有多少比例的事件链能关联到明确的既定威胁场景(比如数据外泄、横向移动、持久化驻留)。这个指标衡量的是图谱在真实攻击研判中的落地效果,防止建出来的图只是在“看起来有联系”而没有实际威胁含义。

第三类是研判效率:分析师完成一次人工研判的平均时长。部署前我们没有精确统计过,但从运营团队反馈看,初期能明显感觉单条告警调研耗时下降;到项目三个月后,一些典型场景的研判时长只有过去的一半。

老实说,单看第一类指标很容易被数据欺骗——关联覆盖率高不代表有效关联多,也许只是大量低价值告警之间建立了很多没有实际意义的边。所以这三类指标必须一起看,才能相对客观地评价项目效果。

7.2 我个人在这段时间里的几点体会

项目做到这里,有些经验想专门写出来。优先把事情做薄是我从MiroFish里感受最深的一点。实体类型、关系类型、查询接口,我们都只保留最刚需的那几个,这保证了项目三个月就能跑通核心链路。安全系统最大的风险不是功能太少,而是功能太多导致没有人持续维护,最终整个系统烂在无人接手的代码里。

第二点是置信度机制需要从第一天就引入,不能等图谱跑大了再补。我们虽然初版就设计了置信度,但实际是在第二个月才真正把它应用在路径排序上,早期没有置信度拦截的时候,图谱里显示出的很多连接其实毫无价值。这个机制引入得越早,后续数据治理的成本就越低。

以后这个项目如果继续演进,主要有两个方向。一是引入更丰富的实体类型,比如把网络协议层面的TCP会话、DNS查询这类更底层的行为也纳入图里,帮助分析师看得更深。另一个方向是进一步压缩人工研判的介入比例,把更多常见的关联路径固化成可复用的图模板,但这一步必须建立在充足的人工确认样本基础上,不能一上来就全自动。项目本身还在跑,我会持续把它打磨下去。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询