过去这两年,做应用安全的人应该都有一个共同感受:漏洞已经不只是“修不修”的问题,而是根本来不及修。Log4j2漏洞爆出来的时候,很多企业连夜排查,最后发现内网躺着几百条调用链;XZ-utils后门事件又给整个行业提了个醒——一个维护了多年的开源项目,也可能在某次版本更新里被植入后门。等CVE公告出来再被动响应,在供应链攻击面前已经明显不够用了。
最近我在做数字供应链安全治理项目,系统性研究了一遍悬镜安全的思路。他们做事的核心逻辑是“风险情报驱动”,这跟市面上大多数只做漏洞扫描的产品完全不是一个路子。简单说,不是把软件成分扫出来、丢给你一份CVE清单就完事,而是把开发、构建、发布、运行整个链条上的风险信号聚在一起,用情报驱动每一次检测、评估和阻断动作。这篇文章我会从治理视角拆解这个方案,讲讲风险情报驱动的具体落地方式,包括资产盘点、SBOM、情报聚合、卡点策略和运行时防护。不管你是正在头疼供应链安全的甲方负责人,还是刚接触SCA和SBOM的安全工程师,按着这个思路都可以少踩不少坑。
1. 数字供应链安全治理:先搞清楚问题边界
1.1 供应链攻击的完整杀伤链:从开发到上线的每层风险
现在的软件开发,绝大多数系统已经不是从零写出来的,而是由开源组件、商业组件、自研代码拼装起来的。任何一个环节被污染,都会顺着依赖关系层层扩散。典型的供应链攻击可以拆成四段来理解。
第一段是依赖引入阶段。攻击者往npm、PyPI、Maven这些公共组件仓库上传恶意包,用和正常包高度相似的包名去制造依赖混淆,等着某个开发者手滑引入。还有一类更阴险,直接攻破有影响力的开源项目仓库,把后门代码混进正式版本里发布。XZ-utils那个事件就属于这种,维护者身份被盗用,恶意代码混进了一个被全世界广泛使用的压缩库。这种攻击之所以可怕,是因为组件本身是“合法”的,传统漏洞扫描完全识别不出来。
第二段是构建阶段。CI服务器如果被入侵,攻击者可以篡改构建脚本、替换编译工具链、往产物里塞私货。很多团队对CI系统的防护远不如对生产环境那么上心,默认账号、弱密钥、开放权限,这类问题在行业里相当普遍。
第三段是发布和分发阶段。制品仓库、镜像仓库如果没有完整性校验和签名机制,恶意代码可能在中途被替换。之前发生过不少镜像仓库里的镜像和官方源不一致的案例,拉取方不做校验就中招了。
第四段是运行阶段。前面几步成功之后,恶意代码会在应用运行环境里真正干活——外传数据、弹shell、横向移动。这个阶段如果没有任何运行时监控手段,攻击者可以在系统里潜伏很久。
这四段风险对应的团队完全不同。开发觉得依赖是别人选的,运维觉得是开发引入的,安全想管又缺一个能贯穿全程的视角。所以供应链安全治理的第一个难点,不是技术,而是先建立一条所有人认账的责任链路。
1.2 传统漏洞扫描为什么会失灵
大多数企业最早是上SCA工具扫CVE。但真正跑过一段时间就会发现,这套打法问题很大。
首先是漏洞库覆盖滞后。NVD的更新节奏跟现实的攻击节奏之间有明显的空窗期。很多漏洞在被安全社区传开、甚至已经在野利用的时候,CVE库还没来得及收录。0day和半公开漏洞最危险的那段时间,传统工具反而是瞎的。
其次是只有版本比对,没有攻击研判。一个组件版本匹配到了CVE,系统就把它标记为漏洞。但现实情况是,很多所谓的高危漏洞根本不在应用的可达路径上——既没有外部请求能触达那个函数,也没有对应的数据流能利用它。结果就是开发每天收到一堆“紧急修复”工单,点进去一看跟自己毫无关系,慢慢就麻了。真正需要优先修的漏洞,反而淹没在大量无效告警里。
更关键的一点是,传统SCA天生对“恶意组件”没有感知能力。一个被植入后门的开源包,它的CVE编号是空的,没有任何漏洞库会记录它“有罪”。但它就是危险的。传统工具的底层逻辑只管“版本有没有匹配到已知漏洞”,对于投毒、混淆攻击、行为异常,它没有对应的检测模型。
用个直白的类比,传统SCA像拿着一份过期地图找路。地图上标了的坑你能躲开,但新挖的坑、正在挖的坑,它完全看不到。在供应链攻击面前,后者才是最致命的。
1.3 风险情报在这里扮演的角色:把漏洞数据变成决策依据
风险情报驱动和传统漏洞扫描的本质区别,是把“有没有问题”变成“会不会被利用、该不该现在处理”。
风险情报不只是CVE编号,而是围绕一个组件、一个资产形成的一整套上下文。一个风险最终被判定为高危,通常需要同时满足几个条件:组件存在已知且可利用的漏洞;这个组件在目标系统的调用链上真实可达;有可用的利用方式或者已经在野利用的迹象;资产暴露面没有缓解措施兜底。
把这些信息汇总之后,安全团队拿到的就不是几百条CVE列表,而是几条真正需要动手处理的风险。悬镜安全做的事情,本质上就是把“漏洞研判”这个依赖资深安全专家人工完成的工作,用产品化的方式沉淀下来。它先帮你把资产底图清出来,然后把多维情报挂上去,最后算出每一台系统、每一个组件的真实风险值。这个值不是一成不变的,情报一变,它跟着变。
这就是治理和扫描的区别。扫描是一次性的体检报告,治理是持续变化的动态过程。把这个问题边界想清楚,你才真的明白为什么要用风险情报来驱动整个供应链安全体系,而不是继续买一堆只会出报告的扫描器。
2. 风险情报驱动的三层技术底座
2.1 第一层:SBOM自动化采集
SBOM(软件物料清单)这个词这几年被反复提,但很多人其实没想清楚它到底用来干嘛。打个比方,你去药店买药,瓶子上会写清楚成分、含量、生产批次。SBOM就是软件系统的“成分表”——完整记录一个软件用了哪些组件、什么版本、来源在哪里、许可证是什么。
为什么要先做SBOM?因为风险情报必须挂在“物”上。你不知道系统里有什么,就不知道情报该关联到哪个资产。SBOM是所有后续治理动作的底图。
实际的采集方式有几种。最优先的是直接解析包管理器的锁定文件,比如Java的pom.xml、Node的package-lock.json、Python的requirements.txt。这类文件记录了构建时的精确版本,准确率最高。其次是用SCA工具对源码、二进制、容器镜像做成分识别。再次是二进制指纹匹配,很多老的组件是编译好的,没有锁定文件,只能靠特征指纹去比对组件库。
这里有几个实操中一定会踩的坑。
第一,锁定文件存在,但实际构建时可能因为依赖解析规则不同,最终跑起来的是另一个版本。这就是为什么一些人觉得SBOM不准的根本原因。所以我一直强调,真正靠谱的做法是构建阶段做依赖快照,而不是事后靠扫的。
第二,自研代码里直接把第三方开源源码拷贝进来了。这种“内嵌组件”在构建记录里根本不存在,但确实运行在你的系统里。这类情况只能靠代码特征扫描才能发现。
第三,容器镜像里套着多层基础镜像。很多企业做完镜像扫描以为覆盖了全部,其实只扫到了最上层应用。底层操作系统、基础运行环境里的组件完全没进SBOM。需要在镜像构建的每一层做成份识别。
悬镜源鉴SCA在这块的做法是源码扫描和二进制指纹结合,输出标准的SPDX或者CycloneDX格式。我比较认可这个设计,因为SBOM不应该困在某个厂商私有格式里。标准格式意味着不管是自研工具、其他平台还是监管审计,都可以直接消费这份数据。
2.2 第二层:多源威胁情报聚合
有了SBOM底图,接下来要往上叠情报。这里的“情报”是分层次的,我把它拆成五类。
第一类是权威漏洞库,比如NVD、CNNVD,记录CVE基础信息,这是最底层的原始数据。第二类是利用情报,某个漏洞是否已经有公开的PoC,是否被集成进了漏洞利用工具包。这个信号比CVE编号本身值钱得多。一个漏洞写了三万字分析文章,但全世界找不到一个可用利用代码,它的现实威胁就有限。第三类是在野攻击情报,来自安全厂商的蜜罐、威胁情报平台、应急响应案例。这个是最能直接驱动应急响应的信号——说明已经有真实攻击者在用了。第四类是恶意组件情报,某个包名、某个制品被标记为恶意,哪怕它没有任何CVE编号。这类情报是传统漏洞库给不了的。第五类是行为情报,也就是组件在运行时的可疑动作,比如异常外联、加密行为、篡改文件、进程注入。
这五类情报来源的格式五花八门,有结构化接口、有PDF通告、有邮件预警、还有人工整理的报告。聚合层要做的就是归一化:把它们统一成同一种结构化数据格式,去掉重复和矛盾信息,再根据来源可信度给每条情报打置信度分数。
一个CVE如果只是被NVD收录,说明业界知道这件事了,但未必有人在打。一旦它进了美国CISA的已知被利用漏洞目录(KEV),意味着已经有人拿它打真实目标了,优先级立刻往上提好几档。这种处理逻辑,普通漏洞库不会帮你做,但情报聚合层可以做。
悬镜这批做供应链安全的厂商,一般都会把开源情报和自研安全团队产出的情报合到一起,形成自己的风险情报数据中心。这样对甲方的支撑就不局限在某一次扫描的瞬间,而是持续滚动更新——今天一个组件看起来没问题,明天一条新的在野利用情报进来,它的风险分就该立刻变化。这个“动态变化”的能力,恰恰是传统SCA给不了的。
2.3 第三层:风险关联分析与可达性评估
情报聚合完,最怕的就是全量报出来。把所有信号不加筛选地丢给安全团队,跟没有情报没什么区别。关键一步是把情报和具体资产关联起来,算出真实风险。
一个风险要不要立刻处理,我一般按下面这个顺序问下去。
这个组件在哪些系统里?从SBOM清单反查,得到受影响的资产列表。漏洞在这个应用的真实调用链上吗?这是最核心的问题。版本匹配不等于可利用,得看应用里是不是真的存在代码路径,能从外部入口一路触达这个组件的风险函数。判断这件事,需要借助SAST的数据流分析,或者RASP、IAST这类运行时工具做调用链追踪。很多团队只看前面两步,不看这一步,误报率自然下不来。
这个资产处于什么暴露面?公网可达和纯内网离线是完全不同的风险等级。有没有缓解措施?WAF规则能不能挡、网络层有没有隔离、组件虽然老旧但功能根本不会被外部触发,这些都会把风险等级往下拉。
把这几个维度综合起来,才能得出一个业务风险分。这个分比CVSS基础分实用得多。一个CVSS评分9.8的漏洞,如果完全不可达,实际风险可能还不如一个CVSS只有7.5但暴露在公网、且已经被人批量打的漏洞。CVSS是学术视角,业务风险分才是运营视角。
风险情报驱动的“驱动”二字,在这里体现得很充分。每个应用的风险分不是扫一次就固定了。情报一变,分就变;资产暴露面变了,分也跟着变;开发把某个组件升级了,分立刻降下来。治理优先级跟着风险分动态调整,安全团队手里永远是一排按真实风险排好序的待办清单,而不是一堆静态报告。
3. 治理实践落地:从0到1搭建体系
3.1 第一步:盘点资产与确定基线
不论你选悬镜还是其他厂商的方案,第一步都是一样的:盘点资产。这是最枯燥、最容易被跳过、但最不能跳过的一步。
具体要盘三样东西。
应用系统清单。哪些是核心业务、哪些是边缘小工具、哪些已经没人维护了,全部登记造册。这一步做的时候你一定会发现,你公司系统数量比你印象中多得多,光新旧系统加起来上百个很正常。
依赖清单。对每个应用做SCA扫描,生成一份SBOM,然后汇总成一个全公司的组件资产库。这样可以知道某个组件到底影响了多少个系统。很多企业在Log4j应急时最头疼的就是这个问题——知道这个组件有问题,但不知道哪些系统用了,只能全网群发邮件让各团队自查。有了组件资产库,一条SQL就能查出来。
构建链路。CI工具是什么,代码怎么编译,制品往哪放,镜像仓库怎么管理。这决定了后面的安全卡点该加在哪些环节。
盘点完了,第二个问题就是怎么定治理基线。我强烈不建议一上来就全量治理。现实情况是,旧系统里躺着大量五年没升级的组件,你想清也清不完,直接推全量大概率项目黄掉。我的建议是先把最脆弱、最重要的切进来:公网暴露的系统、承载核心业务的系统、组件数量特别庞大的系统、历史漏洞最密集的系统。第一批评级做完,其他系统按风险从高到低排队。
这个阶段最重要的产出不是一份漂亮的报告,而是可持续维护的资产台账加SBOM库。后面做情报关联、做告警分析、做应急响应,全靠这份底图。
3.2 第二步:闸口前移,把安全嵌进CI/CD
资产底图有了,下一步是把治理动作嵌到开发流程里。这里关键是想清楚四个集成点。
代码提交后立即触发SAST。自研代码里有没有注入、反序列化这类问题,在人力成本最低的阶段发现。依赖解析时触发SCA校验。构建工具把第三方组件拉下来那一刻,就是对组件做情报查询的最好时机。这时候发现风险,可以最快地阻断引入。镜像构建完成后扫描。把镜像当成一个整体,做成分识别和基线检查,避免把问题一路带到部署环节。制品入库做准入判断。二进制和镜像要进制品仓库之前,必须通过安全校验,不合格就直接拒绝。
卡点规则怎么定?我建议分三级而不是一刀切。
阻断级只留给命中了活跃利用情报的组件,或者漏洞同时在公网暴露且可达的线路上。这种是真实的、正在发生的风险,直接打回,阻止构建或上线。警告级是存在已知CVE但不可达,或者组件风险分还没到阈值。这种允许通过,但记录在案,提醒开发排期修复。记录级则是暂时没有明显利用风险,仅入库持续观测。
很多团队一上来就想全量阻断,这个基本都会翻车。原因很简单:情报系统总有误报,开发被卡上两次,后面就不信任你了。到时候你再怎么解释都没用。我实践下来比较稳的做法是在10到20个核心应用上先试点,把误报率和规则阈值磨平,再逐步推广到全量。
3.3 第三步:运行时持续监测与灰度阻断
静态治理解决的是已知风险,但攻击者手里的0day、新投毒组件,这些是你情报库里还没有的东西。总得有一层能力在runtime兜底。
RASP(运行时应用自保护)的思路是让安全能力长在应用内部。它直接嵌入应用的运行环境,在请求处理链路里实时分析参数、调用链、I/O行为。当一个组件突然开始干它不该干的事——发起外联、读取敏感文件、执行系统命令——RASP能立刻感知。
悬镜的知脉RASP我注意到的点是,它和风险情报的联动不是那种静态绑定的方式,而是平时大部分时间处于监控模式,只记录不阻断,避免误伤正常业务。风险情报中心一旦更新,发现某个组件有新的利用苗头或者行为特征,系统会自动调高针对那个组件的监控等级,甚至在关键时刻自动切入阻断模式。这就是典型的情报驱动策略实时调整,比人工写WAF规则要高效得多。
再说一句灰度阻断。任何防护策略上线之前,先在生产环境观察一段时间,确认告警都是真实风险而不是误报,再全量打开阻断能力。宁可白天多接几个告警,也不要因为一个误阻断把业务打到CTO面前。做安全的,最怕的不是漏报,而是被业务当成制造故障的那个部门。
4. 常见问题与排查技巧实录
4.1 误报率太高,开发不配合怎么办
这是一个供应链安全治理项目落地时几乎必踩的坑。很多安全团队拿着扫描报告去找开发,开发打开一看,几十条高危漏洞,再一查全都不可达,直接就撂挑子了。这种场景我见过太多次。
处理思路有几个。第一,别把原始报告直接转发出去。开发要看的不应该是漏洞编号列表,而是“我的系统里哪些真实链路存在被利用的可能”。在发出去之前,先把报告按业务风险排序,只把真正需要动手的前几条提出来。第二,排查SBOM识别本身准不准。很多所谓的误报,是组件版本识别错了,或者把间接依赖当成直接依赖报了。先把数据层校准,再谈策略。第三,收紧阻断阈值。把“必须修”的范围缩到只有被活跃利用情报加持的漏洞。
开发不配合理由各不相同,但本质都是安全问题成了他们的额外负担。你如果能做到“安全的优先级就是业务的优先级”,把每条告警都讲成业务语言,配合度一定会上来。
4.2 SBOM生成覆盖不全,漏洞排查找不到根
SBOM覆盖不足是非常常见的问题,尤其在老项目里。你可能会发现,明明系统里用的某个组件,扫描结果里就是没有。
建议按这个顺序排查。先检查有没有包管理锁定文件,有就优先从锁定文件生成,比事后扫描靠谱得多。再看二进制组件,这种没有清单可读的,只能靠指纹库匹配。匹配不到就扩充指纹库,或者手工补充记录。特别注意构建阶段动态拉取的那些依赖,事后扫描是漏得最严重的,正确做法是在构建时做依赖快照,让CI流程顺带把依赖清单写进SBOM里。
还有一类情况是开发用了自己搭的私有源,公共仓库里查不到的组件,扫描器怎么都扫不出来。这种必须先接入私有源地址做解析,才能保证覆盖。别等到出事了才发现SBOM是空的。
4.3 情报滞后于攻击,如何补足时间差
坦白讲,任何风险情报体系都有滞后窗口。不可能做到世界上的安全事件第一时间被你看到并立刻联动。但这里有个原则:多信号互相补位。
情报源是分层的,在野利用情报的优先级最高,这种信号一旦出现,就直接触发应急流程,不用等漏洞库收录。上面说的行为情报也很有用,它靠运行时监测补上“情报没来得及同步”的这段真空时间。就算完全没有情报,一个组件反常地外连或者执行命令,RASP也能兜底。
我实践中的一个技巧是定期复盘。每次应急事件结束之后,把时间线拉出来:漏洞公开是什么时候、情报系统入库是什么时候、告警触发是什么时候、实际响应是什么时候。每一段延迟都记录下来,分析延迟出在哪个环节,然后针对性地优化。持续做几次,你的响应速度会肉眼可见地提升。
我自己的体会是,供应链安全治理最怕的不是技术难,而是上来就追求全套工具链。风险情报驱动的本质,是把安全团队从“每天刷漏洞公告、到处救火”里解放出来,让系统自己知道该盯着谁。如果你正在做类似项目,我的建议很朴素:先把资产和SBOM这张底图打出来,再一层层叠情报、卡点、运行时防护。底图越扎实,后面越顺。等到下次再出现类似的事件,你至少第一时间知道哪些系统会受影响,而不是又开着全员大会一起猜。