最近接了个任务,帮某公司搭一套内部的漏洞管理平台。他们之前处理安全通告的方式,说实话挺原始的:安全团队收到一条CVE推送,就开始查内部资产清单,人工比对哪些系统用了受影响组件,再逐个发邮件催修复。等一轮漏洞排查下来,少则两三天,多则一周,期间系统一直暴露着。而且这个流程完全依赖人的经验,人一走,流程就断。
所以这次我直接选了cve-search作为底层引擎,用它搭了一套企业级安全漏洞管理平台。cve-search这个开源项目,本质上是一个CVE漏洞数据聚合与检索系统,能把NVD、CWE、CPE这些数据源定期同步到本地MongoDB,再通过自带Web界面和API做查询。它解决的核心问题是:把“漏洞情报”从分散的网站公告变成结构化的本地数据。
这篇文章我把整个搭建过程、架构思路、踩过的坑都梳理了一遍。从cve-search部署、数据同步、资产指纹建模,到漏洞关联匹配、风险评分、工单闭环,以及最后平台怎么跟现有安全流程结合。适合正在做安全运营、漏洞管理、合规自查的工程师参考,也适合想自己动手搭一套低成本漏洞情报系统的团队。
1. 为什么选择cve-search作为漏洞平台的底座
1.1 cve-search到底是什么
cve-search是一个用Python写的开源工具,核心功能是把CVE漏洞库、CPE产品字典、CWE弱点分类等数据下载到本地,存在MongoDB里,并通过Web界面和HTTP API提供检索能力。
很多人第一反应是:查CVE直接上NVD官网不就行了,为什么要自己搭一套?我刚开始也是这么想的,但实际用下来,官网查询有几个很难受的限制:
第一,NVD官网的搜索主要是“按CVE编号”或“按关键词”查,它没法批量关联你的资产清单。你有一台服务器跑着某个开源组件,你需要的不是“这个漏洞编号是什么”,而是“我手上的软件版本到底命中哪些CVE”。这种批量关联查询,在官网上做效率极低。
第二,NVD的数据更新不是实时的,每天都有批量推送。如果你只是临时查一下还好,但要做持续跟踪,比如每天自动拉取新增漏洞、跟资产匹配、生成报告,就必须有本地数据。
第三,CVE数据量已经非常大,目前NVD收录的CVE超过20万条,而且还在增长。人工翻官网做排查,既慢又容易漏,更谈不上做历史数据分析和趋势统计。
cve-search把这些数据搬到本地之后,你可以用MongoDB的查询能力做灵活分析,也可以调用它的API把漏洞数据接进自己的平台。它本质上不是“一个漏洞扫描器”,而是一个漏洞情报数据底座。
1.2 企业级漏洞管理平台需要哪些能力
真正要落地一个企业级漏洞管理平台,不能只是部署cve-search就完事。你要想清楚,平台最终要服务哪些场景。
我梳理了实际运营中最刚需的几个能力:
资产与版本的持续梳理。漏洞管理的前提是知道“自己有什么”。企业网络里的服务器、中间件、数据库、开源组件、容器镜像,这些都是漏洞的载体。资产清单如果都不全,漏洞匹配就是空谈。
漏洞情报的自动化同步。这是cve-search最擅长的部分,定时从NVD等数据源拉取最新漏洞,存入本地。这样平台不依赖外部接口的实时调用,查询速度更快,也避免了公开接口的访问限制。
资产指纹到CVE的关联匹配。这一步是核心,也是最难做好的。资产指纹要能转化成标准格式(比如CPE),再跟漏洞库中的CPE配置做匹配,才能知道哪些资产受哪个CVE影响。
风险评分与优先级排序。漏洞是无限的,修复资源是有限的。平台必须能输出“先修哪个”,不能只是列一张漏洞清单。这里要用到CVSS(通用漏洞评分系统)分数、EPSS(利用可能性预测)分数、资产重要性等多维信息。
通知、工单与闭环跟踪。发现漏洞只是第一步,后续的派单、修复、复验、关闭,才是漏洞管理真正产生价值的部分。很多开源工具只做到“发现”,剩下的流程要自己接。
这四个能力对应到技术选型上,cve-search解决的是第二个和第三个的一部分,其余的需要你基于它二次开发或者集成其他工具。
1.3 三种技术路线的对比
在决定用cve-search之前,我也考虑过其他方案,这里做一个对比,供参考。
第一种方案是只依赖在线漏洞库查询。比如安全团队手工到NVD网站查,或者写脚本调用NVD的API。优点是没有部署成本,缺点是批量关联能力太弱,API有访问频率限制,数据追溯性差,而且一旦外部服务不稳定就抓瞎。
第二种方案是直接采购商业漏洞管理系统。商业产品的优势是开箱即用,漏洞库、资产扫描、工单流程都帮你做好了。缺点是价格不菲,而且漏洞情报的黑盒机制让你很难自定义数据源和评分逻辑,扩展性受限。对于预算充足的大型企业来说这是OK的,但很多团队其实没这个预算。
第三种方案就是自建,用cve-search做数据底座,配合开源扫描器、自研的资产管理和工单流程。这套方案的好处是数据完全自主可控,漏洞库在自己手里,想怎么分析就怎么分析,成本主要是人力和服务器资源。缺点是需要一定的开发能力,而且cve-search本身有一些不完善的地方需要你补丁式处理。
我最后选了第三种。原因很简单:可控、可扩展、成本可控。但我也要提前说清楚,这条路不是零代码的,需要你自己写一些胶水代码,把这几个环节串起来。
2. 部署cve-search与数据同步实操
2.1 环境准备与基础安装
cve-search的部署不算复杂,但对环境有一些要求。它的核心依赖是Python 3、MongoDB和Redis。
官方文档推荐的是Python 3环境,MongoDB建议4.x以上,Redis用于缓存和一些异步任务。我实际部署用的是一台8核16G内存的服务器,MongoDB单独放在同一台机器上,数据量上来之后建议把MongoDB拆到独立服务器。
安装流程大致是这几个步骤:
# 1. 克隆代码仓库 git clone https://github.com/cve-search/cve-search.git cd cve-search # 2. 安装Python依赖 pip3 install -r requirements.txt # 3. 修改配置,主要是MongoDB和Redis连接信息 cp etc/cve-search.ini.template etc/cve-search.ini vim etc/cve-search.ini配置文件的重点在[Database]和[Redis]这两个段落。默认配置连接本地的MongoDB,如果你把MongoDB装在其他机器上,需要修改host和port。
[Database] host = 127.0.0.1 port = 27017 dbname = cvedb [Redis] host = 127.0.0.1 port = 6379装完之后第一步是初始化数据库。cve-search提供了一个数据库管理脚本,用来自动建立集合和索引:
# 初始化数据库和索引 ./bin/db_mgmt.py -p这个命令会连接到MongoDB,创建名为cvedb的数据库,并建立必要的索引。注意如果MongoDB的认证开启了,记得在配置里加上用户名密码。
2.2 初次全量同步与增量更新
初始化完成之后,就要把CVE数据拉到本地了。cve-search通过db_updater.py脚本来做这件事。
第一次建议做全量同步,把NVD的完整历史数据都拉下来:
# 全量同步,-v显示详细日志 ./bin/db_updater.py -v这一步要有点耐心。NVD全量数据包含几十万条CVE记录,加上CPE和CWE数据,视网络情况可能要跑几个小时。我这边第一次同步大概用了三个多小时,主要是下载和解析JSON文件的过程比较耗时。
同步完成之后,验证一下数据是否完整:
# 进入MongoDB查看CVE数量 mongo cvedb --eval "db.cves.countDocuments()" # 也可以用cve-search的命令行工具查看 ./bin/search.py -c CVE-2024-1234增量更新就简单多了,定时跑db_updater.py就行。脚本会检查上次同步的位置,只拉取新增和修改的CVE,通常几分钟就能完成。
我实际配置的cron任务是这样:
# 每天凌晨2点同步一次漏洞数据,日志轮转 0 2 * * * cd /opt/cve-search && ./bin/db_updater.py -v >> /var/log/cve-search-update.log 2>&1之所以选凌晨2点,是因为NVD的数据更新一般发生在美东时间的白天,换算到北京时间正好是晚上到凌晨。这个时间点同步,第二天上班的时候数据基本就是最新的。
注意:如果你的服务器需要通过代理访问外网,记得在cve-search.ini里配置代理,否则数据同步会一直失败。这个坑我踩过,
db_updater.py报错时会显示连接超时或者SSL错误,排查方向很容易跑偏。
2.3 Web界面与API服务配置
数据同步完之后,cve-search自带的Web界面就可以用了。启动方式有两种,一种是直接跑开发服务器,另一种是用uWSGI做生产部署。
开发模式下这样启动:
cd web ./index.py --port 5000 --host 0.0.0.0测试没问题之后,我建议把Web服务做成systemd服务,保证崩溃后自动拉起。
[Unit] Description=cve-search web After=network.target mongod.service redis.service [Service] ExecStart=/usr/bin/python3 /opt/cve-search/web/index.py --port 5000 --host 0.0.0.0 Restart=always RestartSec=10 User=cve Group=cve [Install] WantedBy=multi-user.target这里说一个安全经验:Web服务不要直接暴露到公网。cve-search的Web界面没有任何认证机制,任何人都能查询你库里的漏洞数据。内部网络部署时,建议只监听内网IP,或者前面加一层反向代理做IP白名单。
API这块也要重点说一下。cve-search提供的HTTP API接口,是我们平台对接的核心。常用的有这么几个:
# 按CVE ID查询 curl http://127.0.0.1:5000/api/cve/CVE-2024-1234 # 按产品搜索漏洞 curl http://127.0.0.1:5000/api/search/apache/tomcat # 按CWE弱点类型搜索 curl http://127.0.0.1:5000/api/cwe/79企业级平台通常不会直接用Web界面,而是通过API把这些数据读出来,再自己拼业务逻辑。我后面讲到的资产关联匹配,就是基于API做二次开发。
3. 资产指纹建模与漏洞关联匹配
3.1 CPE规范与资产建模
漏洞管理最难的一环,不是拿到CVE数据,而是把资产和漏洞正确关联起来。
cve-search的漏洞库中,每条CVE都会带上影响的产品配置,这些产品描述用的是CPE(Common Platform Enumeration)格式。CPE是一种标准化的产品命名规范,格式看起来像这样:
cpe:2.3:a:apache:tomcat:9.0.38:*:*:*:*:*:*:*拆开看:a表示应用,apache是厂商,tomcat是产品名,9.0.38是版本号。后面还有一堆字段,包括更新版本、语言、目标软件、目标硬件等,多数时候用星号通配。
要把资产关联到CVE,前提就是把你公司的软件资产也描述成CPE格式。这里有个很关键的转换过程。
我这边做了一个资产采集的小系统。每台服务器上部署采集脚本,定期上报操作系统、软件列表和版本信息。采集到的原始信息是非结构化的,比如“CentOS Linux release 7.9.2009”“nginx version: nginx/1.18.0”,需要映射成CPE标准格式。
这个映射过程没法完全自动化,因为各家软件的版本号格式五花八门。我的做法是维护一张对照表,把常见软件和对应的CPE格式预先映射好,采集脚本上报后自动匹配。比如:
| 原始指纹 | 标准化CPE |
|---|---|
| Apache Tomcat/9.0.38 | cpe:2.3:a:apache:tomcat:9.0.38:::::::* |
| nginx/1.18.0 | cpe:2.3:a:nginx:nginx:1.18.0:::::::* |
| OpenSSH_7.4p1 | cpe:2.3:a:openbsd:openssh:7.4:::::::* |
有了这个对照表,后续的系统新软件安装、升级,都能自动生成CPE。
3.2 关联匹配策略与查询优化
资产有了CPE之后,就要跟cve-search库里的CVE做匹配。
cve-search提供了按CPE搜索漏洞的能力,但并不是按CPE精确匹配,而是需要你自己处理版本号的范围逻辑。因为一个CVE往往影响某一个产品的多个版本范围,比如“Apache Tomcat 9.0.0到9.0.40之间受影响”。
我之前写过一个关联引擎,思路是:
首先从资产业务库中取出所有资产的CPE,然后逐条调用cve-search的搜索接口,获取命中该产品的所有CVE。这里注意控制并发请求数量,不然cve-search的Web服务会被打满。我这边是控制的并发数在16左右。
取到候选CVE之后,接下来是关键的一步:过滤版本范围。cve-search库中的CVE记录里,vulnerable_configuration字段会列出所有受影响的CPE,这些CPE里有的指定了具体版本,有的是版本范围(用版本号+通配符表示)。需要自己解析这些规则,判断资产的版本号是否落在受影响范围内。
这里给一个简化的版本判断逻辑伪代码:
def is_vulnerable(asset_cpe, vulnerable_cpe_list): for vcpe in vulnerable_cpe_list: if cpe_product_match(asset_cpe, vcpe): if version_in_range(asset_cpe.version, vcpe.version_range): return True return False版本范围判断有个麻烦:CPE里的版本号经常不标准。比如有的写9.0.*,有的写-表示所有版本,有的写1.0到2.0之间但没有明确界限。这块逻辑需要写得很健壮,我在实际开发中花了大量时间在处理各种版本号边界情况。
3.3 风险评分与优先级排序
漏洞关联出来之后,一大堆CVE列在面前,到底先修哪些?
只看CVSS分数是不够的。两个都是9.8分的漏洞,一个是POC公开且已被利用,另一个只是理论分析异议较大,修复优先级应该完全不同。
我的做法是按CVSS基础分、EPSS利用概率、资产重要性、漏洞是否已出现在KEV(Known Exploited Vulnerabilities)目录这四维来打分。
CVSS分数不用自己算,cve-search的数据里已经带了。cve-search同步的数据中,每条CVE都有cvss和cvss3字段,分别是CVSS v2和v3的评分。这里注意,有的CVE没有CVSS v3评分,要用v2兜底。
EPSS这个数据源很重要,它是由FIRST组织发布的,每天更新的漏洞利用概率预测。数值范围是0到1,表示这个漏洞未来30天被利用的可能性。我每天写一个定时任务,从EPSS官方源拉取数据存到MongoDB,再按CVE编号关联到漏洞库上。
综合评分的逻辑大致是这样:
risk_score = cvss_score * 0.4 + epss_score * 20 * 0.3 + asset_weight * 0.3 if in_kev: risk_score = min(10, risk_score + 2)这里乘20是因为EPSS值通常远小于1,得放大到与CVSS同一量级,具体权重可以根据自己团队情况调整。识别出来的高风险漏洞,在平台页面里置顶展示,并自动生成待处理工单。
实践心得:EPSS是一个很实用的参考维度,但不要迷信它。它的预测基于历史利用数据,对于新发布的0day漏洞,EPSS分数可能很低。平台里要保留人工复审通道,当安全情报提到某漏洞正在被活跃利用时,可以直接人工提高该漏洞的风险等级。
4. 平台功能扩展与安全流程落地
4.1 自动化扫描与漏洞检测集成
cve-search解决了漏洞情报的问题,但漏洞发现不能只靠资产上报。资产上报是“我告诉平台我有什么”,企业内部经常存在未纳管资产,或者资产上报的数据已经过期。所以我在这套平台上额外接入了主动扫描能力。
扫描这部分我选的是开源扫描器,通过调度任务定期执行。扫描目标从内部CMDB(配置管理数据库)中拉取IP段,扫描结果会跟cve-search的漏洞库做交叉验证。
具体流程是:扫描器发现某服务器上运行着Apache Tomcat 9.0.38,这个指纹同步到资产库后,资产库的变更事件会触发关联引擎,自动去cve-search查Tomcat 9.0.38的漏洞记录,并把命中的CVE更新到该资产的漏洞列表中。
主动扫描和资产上报两个渠道的数据会做合并,同一条CVE可以同时看到“资产上报发现”和“扫描器发现”两个来源,这样能判断这个漏洞的可信度。
4.2 通知推送与工单闭环
漏洞平台做得再好,如果安全团队发现了漏洞,运维团队迟迟不动手修,价值就打了个对折。所以通知和工单闭环是平台必不可少的部分。
我的做法是基于规则引擎做自动派单:
- 高危、严重漏洞,且资产属于核心业务区,立即生成紧急工单;
- 中危漏洞,合并到每周的风险通告邮件中统一派单;
- 低危漏洞,每月汇总一次,纳入常规版本更新计划。
工单系统对接的是内部已有的工单平台,通过API创建工单。每张工单包含资产信息、漏洞详情、CVSS/EPSS评分、修复建议等字段,避免运维人员还需要去查一遍CVE。
闭环流程里还有一道“修复验证”的步骤。运维反馈漏洞修复完成之后,平台会自动重新采集该资产的指纹信息,重新关联CVE,如果漏洞还在,工单自动打回;如果确认修复了,才允许关闭工单。
这里有一个容易被忽略的环节:修复过程中,版本升级可能导致新的漏洞引入。比如为了修一个老漏洞,把Tomcat升级了大版本,结果新版本有其他未修复的CVE。平台在验证关闭工单的同时,要跑一遍全量关联,把新引入的漏洞同步展示出来。
4.3 厂商安全公告与自用CVE数据补充
NVD的数据并不是全的,很多CVE在NVD上会有延迟收录的问题,或者某些厂商漏洞有自己的编号体系。所以平台在cve-search之外,我还加了一个厂商安全公告的采集模块。
这部分需要一个爬虫或者RSS订阅机制,比如关注一些主流开源组件的官方安全公告渠道。采集到的公告会解析出影响版本和CVE编号,更新到自建的公告库中,然后同样走资产匹配逻辑。
我这边还维护了一个“自研漏洞库”。有些内部开发的组件出现了安全问题,不一定能发CVE编号,平台把这些内部漏洞单独存储、单独管理。这样整个漏洞库就分成了三层:公开CVE库、厂商公告库、内部漏洞库。查询的时候先合并,再统一走评分逻辑。
构建自己的数据体系时注意,cve-search的cvedb数据库里可以增加自定义集合,不影响它原有的数据。但官方升级脚本可能不会保留你的自定义字段,升级前做好备份,升级后跑一个自定义字段回填脚本。
5. 常见问题与排查技巧实录
5.1 部署期最容易踩的三个坑
第一个坑:MongoDB版本兼容。cve-search对MongoDB的版本要求比较严格,我用高版本的MongoDB在导入数据时报过格式错误。如果你遇到类似问题,先别急着查代码,看看本机MongoDB和cve-search要求的版本是否匹配。
第二个坑:同步超时或中断。NVD的数据下载比较慢,如果网络不稳定,db_updater.py跑一半就挂了。脚本本身有断点续传能力,但偶尔会出现数据不完整的情况。我建议在同步脚本里加上异常检测:同步结束之后,检查db.cves.countDocuments()的数量,如果低于昨天记录的数量,说明同步有问题,得告警出来。
第三个坑:Redis没配置好。cve-search在某些版本里会用到Redis做缓存,Redis没启动或者连接失败时,Web界面能打开但搜索会非常慢,而且日志不报明确的错。排查时先确认Redis连接是正常的。
5.2 数据匹配不准的排查思路
资产-CVE匹配不准,是使用过程中最让人头疼的问题。
我遇到过不少匹配不准确的情况:平台报某个资产存在某个CVE漏洞,运维去核查发现版本号根本对不上。这种一般有三个原因:
一是资产指纹没更新。资产上软件版本已经升级了,但采集任务还没跑到那台机器。解决方法是缩短采集周期,并且在修完漏洞后立即触发一次采集。
二是CPE映射错误。资产上报的原始版本号和标准化CPE映射错了。比如Tomcat 9.0.38被映射成了9.0.3,这种低级错误在人工维护对照表时很容易出现。建议在对照表里增加校验规则,版本号位数不一致时直接报异常。
三是版本范围判断逻辑有边界bug。CVE记录的漏洞版本范围往往是一个区间,区间边界的处理稍有不当就会误判。比如某个漏洞“Apache Tomcat from 9.0.0 before 9.0.40”,意思是9.0.40以下版本受影响,9.0.40本身不受影响。解析时要特别处理这种“before”边界。
5.3 性能与扩容经验
cve-search的性能问题主要出在查询上。当资产数量达到一定规模,频繁调用搜索接口时,MongoDB的压力会明显上升。
我遇到的问题是:资产从几百台扩展到几千台之后,每天跑关联匹配的时间越来越长,从最初二十分钟延长到两三个小时。排查下来发现瓶颈在MongoDB的查询上,因为没有对cpe字段建索引,导致每次搜索都做全表扫描。
解决办法是在cves集合上对cpe字段和id字段建索引,同时在cpe集合上对id字段建索引:
db.cves.createIndex({"cpe": 1}); db.cves.createIndex({"id": 1}); db.cpe.createIndex({"id": 1});索引建完之后,查询速度快了很多。这里建议把索引脚本写到部署文档里,新环境配置好之后第一时间执行。
数据量增长到一定程度之后,还要考虑MongoDB的存储规划。CVE数据主要是文本,占空间不算大,但加上索引之后增长量会明显增加。建议给MongoDB单独分一个数据盘,并且做好容量监控,别等写满了下游所有服务一起挂掉。
5.4 平台日常维护清单
平台上线之后,日常维护主要就是这几件事:
每天检查同步任务是否成功,CVE数量是否正常增长;每周检查资产指纹采集覆盖率,发现长期未更新的资产要排查原因;每月跑一次关联匹配全量任务,把漏掉的历史漏洞补上;每次cve-search版本升级前,做好数据库备份和兼容性测试。
我自己用的脚本是这样安排的:同步任务每天跑,资产采集每周一次全量、每天一次增量,关联匹配在资产采集和CVE同步完成后自动触发。所有任务都挂在同一个监控系统上,失败就告警。
另外建议把cve-search的Web和API服务设为开机自启,加上systemd守护进程,避免服务器重启后服务挂掉但没人发现的情况。
最后分享几个实操小技巧
项目收尾之后,我再补三个细节,都是实际使用中抠出来的经验。
第一个技巧,关于漏洞修复验收的“二次扫描”。运维提交漏洞修复后,别只看他们填的修复结果。平台的自动复验功能要保留证据:修复前和修复后的资产指纹、关联CVE列表的diff记录,都要留档。这样万一验收后漏洞复发,你有迹可查。我在平台上加了这条审计流水,审计时帮了不少忙。
第二个技巧,关于CVE数据与业务线隔离。如果你所在的企业有多条业务线,资产归属不一致,可以在资产上打上业务线的标签,漏洞工单自动按业务线分派。这个功能建议一开始就设计进去,后补的话涉及资产库、工单系统、权限控制多个模块,改动量不大但很牵扯精力。
第三个技巧,关于漏洞报告模板。平台上了之后,管理层可能会定期要报表。我建议提前设计好两套报告模板:一套是给技术团队看的,指标是漏洞数、修复率、平均修复时长;另一套是给管理层看的,突出风险趋势、重点风险项、资源需求。两套报告的底层数据是一样的,只是展示口径不同。不要在领导要看报告的时候才临时导数据,常态化的报表输出能力,才是平台价值的体现。
整套平台从部署到稳定运行,核心不在于代码写得有多漂亮,而在于把漏洞情报、资产数据、修复流程这三件事真正串成了一个闭环。数据源头靠cve-search兜底,资产建模靠自己的采集系统,流程闭环靠工单系统,每一环都有活得干,但整体跑通之后,安全团队从“每周加班人工排查漏洞”变成了“每天打开平台看数据”,效率提升是很明显的。