安全设备最尴尬的一点是:它一直在产生数据,但出事的时候你查不出来。
我维护过一套日志系统,每天几千万条记录,真到要回答「这台机器三天前有没有连过那个地址」的时候,人得写半天查询语句,还经常写错。
后来我把这堆日志重新组织成了一张图,查询就变成了「顺着关系走」。这篇说清楚图结构到底解决了什么问题,以及它在什么规模下才开始划算。
关系型查询为什么会卡住
先说传统做法的问题。
日志是「事件流」:谁在什么时候做了什么。用关系库存它,每一次「关联查询」都是多表连接。查两个 IP 之间的关系,要做一次连接;查三层关系(人 → 机器 → 外连地址),就要做两次连接。
半径每扩大一层,查询成本就翻一倍。这还只是成本问题,更麻烦的是写查询的人——他得先知道表结构,才能问出正确的问题。
分析场景的痛点是:你事先并不知道要问什么。
图结构把「关系」变成了一等公民
换成图之后,数据分成两类:
- **点**:账号、主机、IP、域名、文件哈希
- **边**:登录、连接、下载、执行
一旦以这个形态存下来,「查两个东西之间有没有关系」就变成了一次图遍历,跟半径几乎无关。
更重要的是问法变了。原来要写多表连接,现在可以问:
- 这个 IP 还跟哪些主机有过连接?
- 有哪些账号在最近 7 天访问过同一批主机?
- 从这个域名出发,几步之内能到达核心资产?
图查询的价值不是更快,是让不会写 SQL 的人也能问出对的路径。
时间序列要分开存
这里有个容易踩的坑:把所有数据都塞进图。
日志里绝大部分是「计数型」信息——某台机器每小时的连接数、失败登录次数。这类数据用图存是浪费,用时间序列库才合适。
我的做法是两边分工:
- **图**存关系,撑「谁和谁有关系」
- **时间序列**存指标,撑「什么时候开始不对劲」
- 两边用实体 ID 对齐,报警时互相引用
只把图当关系网、把指标当温度计,各司其职,查询才不会两头都不讨好。
落地时的四个实际问题
一是数据量。 全量入图之前必须先聚合。我按「小时」粒度折叠重复事件,把同一主体对同一目标的多次行为压成一条带计数的边,节点规模降了一个数量级。
二是时效。 图适合做回溯分析,不适合做实时阻断。需要毫秒级拦截的场景,还是得靠规则引擎。
三是权限。 图一旦建起来,它天然把所有信息连在一起。谁能查、能查到第几跳,必须提前定好,否则一张图就等于把所有内部信息摊开了。
四是别追求全自动。 我们最后是把图查询做成辅助工具:分析师提问,图给出候选路径,人判断。全自动的「关系推理出攻击链」听着厉害,实际误报率高得没法用。
什么时候值得上
我的判断标准很朴素:当你开始反复问「这两个东西有没有关系」,并且问的半径超过两层,就该考虑图了。
如果只是「查某个 IP 今天做了什么」,那用日志检索就够了,不必引入图。上了图反而多一套要维护的东西。
说点实在的
图数据库不是让日志变聪明的魔法,它只是把「关系」从一个需要计算的成本,变成了一个可以直接问的问题。
真要做,我的建议是先选一个最想回答的问题,围绕它建最小的图,跑通了再扩。上来就想着「把全部数据都连起来」,最后大概率是一张谁也维护不动的图。
本文不构成任何技术选型建议,具体方案请结合实际数据规模评估
建图的顺序
- 1定问题先选一个最想回答的问题,围绕它决定要连哪些关系
- 2抽实体把日志里的主体统一成节点,做去重与归一化
- 3连关系补上时间、位置、设备等边,并标注来源与置信度
- 4留时序高频事件留在时间序列里,不要塞进图里
- 5灰度验证用已知案例验证查询结果,再扩数据源
。