ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Dependency-Track实战:SBOM驱动的持续依赖漏洞监控

Dependency-Track实战:SBOM驱动的持续依赖漏洞监控 半年多以前扫过一遍依赖报告归档在某个共享盘里今天某个公共组件爆出高危漏洞团队第一反应是翻报告——可那份报告只能说明当时没问题。这就是绝大多数依赖扫描的真实处境扫描动作完成了风险监控却没建立起来。Dependency-Track 解决的正是这件事它不是又一个扫描器而是一个持续运转的软件成分账本把每个项目用到的组件版本登记在案然后反复拿这些版本去比对最新公开的漏洞情报一旦某个老项目里躺着的依赖被披露有问题你能立刻定位到底是哪几个项目、哪个版本、被谁引用。本文按从部署到跑通再到日常使用的完整路径展开适合已经接触过 SBOM 概念、想把依赖治理从季度巡检变成实时盯防的开发、测试和安全的同学也适合完全没部署过这类平台、想先跑一套环境看看效果的新手。1. 从扫一次就归档到天天盯着看它到底补的是哪块短板1.1 一次性扫描方案留下的三个断点绝大多数团队最早接触的依赖检查都是集成在构建流程里的那一类构建时跑一遍发现问题就阻断不阻断就出份报告。这个模式听着很严实际跑下来有三个明显的断点。第一个断点是信息只在构建那一刻有效。今天的构建用的是 Spring 的某个版本构建通过、报告清零、大家心情舒畅三个月后这个版本被披露存在反序列化风险但没有任何机制会主动回来告诉你你线上跑的那个服务还挂在这个版本上。漏洞披露是持续发生的扫描却是一次性的两边的时间轴对不上。第二个断点是扫描结果散落在各个流水线的构建产物里。十个项目十条流水线每份报告格式不一样、存放位置不一样、保留策略也不一样。真要回答这个漏洞影响我们哪些服务得挨个翻翻完还得自己人工比对版本号效率极低而且极容易漏。第三个断点是版本号的口径不统一。构建工具里写的是1.2.3传递依赖实际引进来的是1.2.4有的包管理器还会把版本写成范围表达式。人工看依赖树时很容易把声明版本当成实际版本最后得出的结论是错位的。Dependency-Track 的定位就是把这些断点一次性补上。它自己不做代码扫描不分析你的源码只做一件事接收一份标准化的组件清单长期保存持续比对漏洞情报并在状态变化时通知你。1.2 SBOM 是账本漏洞库是流水平台负责对账理解这个工具抓住两个概念就够了。SBOM软件物料清单本质就是你项目的一份配料表。它按标准格式描述了这个应用里包含哪些组件、每个组件什么版本、由谁发布、通过什么方式引入。目前流通最广的两种格式是 CycloneDX 和 SPDX前者在安全场景下用得更多生态也更全主流构建工具基本都有对应的插件能直接吐出来。漏洞情报源就是持续更新的问题公告。平台内置了几个分析器会定期把公开漏洞库里的条目拉下来建立本地索引然后用 SBOM 里的每个组件去索引里查。平台的价值就体现在对账这个动作可以无限次重复。你把 SBOM 传上去之后它不会像扫描器那样跑完就出结论而是会拿着这份清单里的每个组件反复去查最新情报。今天没问题的组件下个月可能就有问题了平台会自动把状态从无风险改成有风险并按照你配的规则推送出来。这个机制听起来简单却是整个依赖治理链条里最难靠人工维持的一环——因为它要求的是每天都做一遍而人做不到机器可以。需要注意的一点平台的风险判断完全依赖公开情报的时效性和准确性。它告诉你这个版本被披露有某某问题不代表你的代码真的调用了那段有问题的逻辑实际可利用性还得结合调用路径自己判断。2. 部署前先想清楚组件构成、资源盘子与数据库选型2.1 三个进程各管什么端口怎么分Dependency-Track 的服务端不是单体标准部署下要跑两个 Java 进程加一个数据库。API 服务端是核心负责接收 SBOM、跑分析器、管理项目与策略、对外提供 REST 接口默认监听 8080。前端服务端是一个独立部署的静态资源加反向代理容器默认也监听 8080它只负责渲染界面所有数据交互都是浏览器直接打到 API 服务端。数据库存项目、组件、漏洞关联、策略这些结构化数据。这里有个新手特别容易栽的坑两个容器默认端口都是 8080如果直接映射到宿主机又不改端口必然冲突。我一般会这样规划API 服务端映射到宿主机 8081前端映射到 8080浏览器访问 8080 上的界面。同时前端的API_BASE_URL环境变量必须指向浏览器能访问到的 API 地址而不是容器内部的localhost。写成http://localhost:8081只在你本机浏览器直接访问时有效如果部署在服务器上就得写成服务器 IP 或域名否则界面能打开但所有请求都 404让人一脸懵。2.2 数据库选型演示用内嵌长期用外部API 服务端支持两种数据库模式。一种是内嵌的嵌入式数据库零配置容器一启动就能用适合本地评估、写 Demo、临时验证。另一种是外部的 PostgreSQL适合任何要长期跑的场景。我强烈建议只要不是纯本地试验一律上 PostgreSQL。原因很实际内嵌模式的数据文件挂载在容器卷里一旦容器重建、卷没挂对、或者升级时镜像行为变化数据说没就没了而且内嵌模式在并发写入和大量组件索引时的表现明显吃力项目数量上去之后查询会变得很慢。PostgreSQL 则是成熟方案备份、迁移、扩容都有现成手段。资源方面给一个参考盘子项目数在 50 个以内、每个 SBOM 几百个组件API 服务端 2 核 4G、PostgreSQL 2 核 2G 基本够用如果要长期保留完整的漏洞库索引API 服务端内存建议给到 4G 以上因为漏洞库全量索引加载起来体积不小内存不足会导致频繁 GC表现为界面越用越卡。磁盘上留出至少 20G 给数据库漏洞库索引和组件记录都会持续增长。部署时区也要留意。容器默认时区往往是 UTC导致界面上的时间戳和你本地差 8 小时排查到底什么时候同步的时很容易误判。建议给容器统一挂上时区环境变量。3. 把服务拉起来一份能直接复用的编排配置3.1 编排文件逐段拆解下面这份配置是我在测试环境反复用过的基础版本三个服务、数据卷持久化、端口错开拿来改改就能用。version: 3.8 services: dtrack-apiserver: image: dependencytrack/apiserver:4.11.3 container_name: dtrack-apiserver environment: - ALPINE_DATABASE_MODEexternal - ALPINE_DATABASE_URLjdbc:postgresql://dtrack-postgres:5432/dtrack - ALPINE_DATABASE_DRIVERorg.postgresql.Driver - ALPINE_DATABASE_USERNAMEdtrack - ALPINE_DATABASE_PASSWORDchange_me_strong - ALPINE_CORS_ENABLEDtrue - ALPINE_CORS_ALLOW_ORIGINhttp://192.168.10.20:8080 - TZAsia/Shanghai volumes: - ./dtrack-data:/data ports: - 8081:8080 depends_on: - dtrack-postgres restart: unless-stopped dtrack-frontend: image: dependencytrack/frontend:4.11.3 container_name: dtrack-frontend environment: - API_BASE_URLhttp://192.168.10.20:8081 - TZAsia/Shanghai ports: - 8080:8080 depends_on: - dtrack-apiserver restart: unless-stopped dtrack-postgres: image: postgres:15-alpine container_name: dtrack-postgres environment: - POSTGRES_USERdtrack - POSTGRES_PASSWORDchange_me_strong - POSTGRES_DBdtrack - TZAsia/Shanghai volumes: - ./pgdata:/var/lib/postgresql/data restart: unless-stopped几处值得单独说明的地方。ALPINE_CORS_ALLOW_ORIGIN必须填前端的完整访问地址包括协议、IP、端口一个字符都不能差。这是浏览器同源策略的要求填错的表现是登录页面能刷出来但点登录按钮一直转圈浏览器控制台里全是跨域报错。我第一次部署时就因为这个卡了半小时一直以为是后端没启动。./dtrack-data:/data这个挂载是 API 服务端的持久化目录里面会存配置文件和临时数据。注意宿主机目录的属主权限容器内进程以非 root 用户运行如果目录属主是 root 且权限是 755写不进去日志里会报权限拒绝。稳妥做法是提前创建目录并放开写权限。镜像版本号建议锁定具体小版本别用latest。这个项目的版本迭代节奏不慢跨大版本升级时数据库表结构可能有变化用latest意味着某次重启就悄悄换了版本出问题时排查方向会被带偏。3.2 首次启动与初始账号处理编排文件就位后docker compose up -d拉起然后用docker compose logs -f dtrack-apiserver盯日志。启动时间取决于机器性能通常一两分钟能起来看到类似server started的字样就说明 API 服务端就绪了。数据表结构会在首次启动时自动初始化这个过程也需要时间期间前端访问会报各种奇怪的 500属正常现象耐心等。初始账号是内置的 admin密码同样有默认值。各版本的具体默认口令请在启动完成后查阅对应版本的官方部署说明不要凭记忆输。登录后第一件事就是改密码第二件事是创建一个专用的 API 账号。这个平台的角色权限设计得比较细日常给流水线用的是只有上传 SBOM 权限的账号不要图省事直接拿 admin 的密钥往 CI 里塞。创建 API 密钥的路径在 管理 → 访问管理 → 团队新建团队、分配权限、生成密钥密钥只在生成时显示一次记得当场记下来。如果你是升级而不是新建务必先备份数据库再确认目标版本的升级说明里有没要求先跑某次中间版本。跨大版本直接跳很容易卡在表结构迁移上。4. 接上情报源漏洞分析器怎么配才不白跑4.1 漏洞库同步配额、节奏与首次全量的代价平台跑起来不等于能查漏洞还要把情报源接上。主力的公开漏洞库需要申请一个访问密钥免费申请但有速率限制。这个限制是双刃剑不填密钥也能用只是拉取速度极慢全量同步可能要跑很久填了密钥速度明显提升但短时间内频繁请求会被限流返回 403 甚至临时封禁。配置入口在 管理 → 分析器 → 对应的漏洞库分析器填密钥、勾选启用。保存之后平台不会立刻开始拉需要手动触发一次全量同步或者等定时任务。首次全量同步是最考验耐心的一步我见过跑了三四个小时还没结束的。原因有两个一是数据量本身就大二十多万条漏洞记录加上关联的组件标识二是每拉一批要落库建立索引。这个过程中可以随时在界面上看同步状态别重启容器重启会中断并可能导致部分数据重复处理。同步完成后还有个容易忽略的点增量更新的频率。默认配置下是每天跑一次增量这个频率对绝大多数团队够用。如果你们对新生漏洞的响应要求很高可以调高频率但要权衡水源的限流风险别把自己搞得被拒绝访问。4.2 分析器各管一摊别指望一个包打天下平台内置的分析器不止一个分工不同。漏洞库分析器负责比对 CVE 类公开漏洞是主力。另一个常见的分析器基于第三方组件情报服务除了漏洞还会给出组件的维护状态、是否有新版本等信息需要单独注册账号同样有免费额度限制。此外还有一些针对特定生态的分析器比如检查组件是否已被官方废弃、检查许可证合规等。我踩过的一个坑是只开了漏洞库分析器就一直以为组件生命周期这类信息也会自动出现结果界面上那几列一直是空的。后来才明白不同的分析器要在 分析器 页面逐个启用而且有一些需要额外凭据。另一个细节是分析器启用后对已有数据的影响。新启用一个分析器它不会自动回扫所有历史项目需要手动触发重新分析。项目数量多的话这一步耗时也不短。建议在部署初期就把要用的分析器一次性配齐避免后面反复补扫。5. 把依赖送进去SBOM 从哪来、怎么传5.1 生成清单先用构建工具自带的插件最省事的方式是用各语言生态现成的插件在打包阶段顺手生成。Java 项目加一个 Maven 插件绑定到package阶段构建完target目录下就多出一份 CycloneDX 格式的 JSONNode 项目有对应的命令行工具npx直接跑容器镜像可以用镜像扫描工具以 CycloneDX 格式输出。Go 和 Python 也都有成熟插件。有个细节值得强调清单要包含传递依赖否则等于白做。很多团队的依赖问题不在自己直接声明的那几个包上而在第三层、第四层被间接引进来的包。生成时确认工具的参数里包含了完整依赖树的解析而不是只读一下清单文件。生成出来的文件我习惯先人眼看一眼重点看三个地方metadata.component里的项目名和版本对不对、components数组的长度是不是符合预期、每个组件有没有purl字段。purl是包的唯一标识形如pkg:maven/group/artifact1.2.3平台靠它来精确匹配漏洞记录。缺了purl的组件匹配率会直线下降等于摆在那里但查不出问题。5.2 走 API 上传一条 curl 打通全流程界面上的上传 BOM按钮适合手工验证真正要用起来必须走接口。核心接口是PUT /api/v1/bom用 multipart 表单提交。export DT_URLhttp://192.168.10.20:8081 export DT_API_KEY你的密钥 export PROJECT_UUID项目的唯一标识 curl -sS -X PUT ${DT_URL}/api/v1/bom \ -H X-Api-Key: ${DT_API_KEY} \ -H Accept: application/json \ -F project${PROJECT_UUID} \ -F autoCreatetrue \ -F bomtarget/bom.json几个参数的实际含义得说清楚。project传的是项目 UUID不是项目名这个值在项目详情页的地址栏里能看到。autoCreatetrue表示如果这个 UUID 对应的项目不存在就自动创建配合项目名和版本可以在某些接口变体里一并指定。bom是文件字段。上传接口是异步的返回 200 不代表处理完了只代表收到并入了队列。真正的处理结果要看响应里的 token再拿 token 去查处理状态或者在界面上看项目的BOM 处理页面。我第一次接入时看到 200 就以为成功了结果刷新项目一看组件数是 0回头查才发现处理失败了——原因是文件格式不合法。autoCreate这个开关是把双刃剑。开着的确省事但一旦项目名或版本算错会在平台里悄悄造出一堆名字相近的重复项目清理起来很烦。我的做法是流水线里首次上传前先用接口查一下项目是否存在不存在就显式创建并把 UUID 落下来写进流水线变量之后固定用这个 UUID 上传autoCreate只在本地试验时开。5.3 接进流水线位置比工具更重要SBOM 上传放在流水线的哪一步直接影响数据的可用性。放在构建成功之后、部署之前是最合理的。此时依赖已经解析完成清单是准确的如果上传失败可以让流水线继续因为上传失败不该阻断业务发布但要在日志里明确告警出来。有一个取舍要提前想是按每次构建都上传还是只在主干分支上传我的经验是主干分支每次构建都传特性分支只在需要评审时手动传。原因是平台里每个项目对应一个 UUID如果每个特性分支都建一个项目项目列表会爆炸而且这些短期分支的漏洞状态没人看。主干持续覆盖上传的好处是同一个项目的组件清单始终反映最新状态漏洞关联会自动跟着更新。还有一个容易忽略的配置项目的版本维度。同一个服务有 1.0、2.1 多个在跑是建一个项目还是按版本建多个平台的模型是项目 版本一个项目下可以有多个版本。实践中我把服务作为项目把发布版本作为版本这样既能看某个版本的具体情况也能在项目层面看到整体风险分布。6. 从发现到有人管策略规则和通知怎么配6.1 策略粒度别一上来就全量告警平台默认有一套策略比如发现某个严重级别以上的漏洞就标记违规。这套默认规则在项目少的时候还行项目一多就是灾难——几千个组件里总有那么几十个带着各种历史遗留的中低危问题通知渠道天天响响到最后所有人都麻木了真出高危反而没人看。我的建议是按影响面 可利用性分层建策略而不是按严重级别一刀切。策略维度规则示例违规动作适用场景严重级别硬门槛严重级别为最高档且组件为直接依赖标记为拒绝对外服务项目版本状态存在已修复的新版本且当前版本落后两个大版本标记为需关注全部项目许可证约束命中特定许可证清单标记为需关注对外分发的产品组件活跃度组件所属项目已停止维护超过一定时间标记为需关注核心系统排除规则明确判定为误报的组件版本对忽略全部项目忽略这个能力一定要善用。有些漏洞在特定使用方式下根本不可利用比如某个库的问题出在一个你完全没调用的功能模块里。这种反复被报出来、团队已经确认无风险的条目就应该进白名单否则会持续污染告警信噪比。白名单要写明原因和确认人别让它变成一键消音。6.2 通知渠道分层推送控制噪音通知配置的模型是规则 发布器 模板。规则定义什么条件下触发发布器定义往哪发模板定义消息长什么样。渠道选择上我最推荐接团队日常用的即时通讯工具的 Webhook因为消息进了大群相关的人都能看到不容易被邮件规则过滤掉。邮件适合作为周报汇总不适合实时告警。推送分级很有必要。最高级别的违规直接推到主频道并 相关值班人中等级别推到单独的告警频道每天汇总一次全部违规的完整清单做成定时报表一周发一次。这样既保证高危能被立刻看到又不会让日常讨论被大量噪音淹没。模板内容要定制默认模板信息太少。我一般会往里面加三样东西项目名和版本、组件的完整坐标和当前版本、以及平台里该项目的直达链接。加了链接之后收到告警的人点一下就能看到上下文响应速度会明显快很多。通知触发是有节流的同一组件的同一状态不会反复推。但如果你频繁重新上传 SBOM可能会看到状态在违规和正常之间来回跳导致通知重复。根源往往是不同流水线传了不同版本的清单互相覆盖排查时先看最近几次上传的时间戳。7. 跑起来之后才会遇到的问题几个真实的排查记录7.1 组件明明在清单里为什么漏洞查不出来这是被问得最多的一类问题表现是 SBOM 上传成功、组件数量也对但某个已知有漏洞的组件就是没有关联出漏洞。排查下来原因基本集中在三种。第一种purl缺失或格式不规范。平台匹配漏洞靠的是包的生态、命名空间、名称、版本这四个要素任何一个不对就匹配不上。有些生成工具默认不输出purl或者把 Maven 的 group 和 artifact 拼错了位置看起来很相似但匹配失败。验证方法很简单进组件详情看标识符字段是不是空的。第二种版本号被规范化了。有类包的版本里带前导 v、带额外的元数据后缀、或者是范围表达式生成工具解析后写进清单的可能是规范化之后的形态而漏洞库里的版本区间是按原始形态描述的。这类问题比较隐蔽需要在组件详情里对照实际声明版本看一眼。第三种漏洞库还没同步到这条记录。公开漏洞从披露到进入各个漏洞库有延迟短的几小时长的几天。如果漏洞是昨天刚公布的查不出来很正常。这时候可以看漏洞库里该条目的最后修改时间来判断。排查顺序我一般这么走先看组件标识符有没有、对不对再看这个组件在平台里的分析面板看分析器有没有跑过、有没有报错最后才是怀疑漏洞库数据的时效。7.2 内存与同步那点事几个能省下大量时间的配置跑一段时间后最常见的抱怨是卡。界面加载慢、项目列表转圈、分析任务排队。第一个抓手是API 服务端的内存。这个服务的默认堆内存偏保守项目多、组件多的时候会频繁 GC。给容器配置合理的内存上限并通过环境变量设置 JVM 堆大小通常调到 4G 以上会有明显改善。但别把容器内存限制和堆大小设成一样大留出四分之一的余量给堆外内存和系统否则容器会被 OOM 直接杀掉比卡更麻烦。第二个抓手是数据库连接池。默认连接数在小规模下够用并发上传多个 SBOM 时会看到连接等待超时。适当调大同时确认 PostgreSQL 的最大连接数配置跟得上两头不匹配一样会报错。第三个抓手是分析任务的并发度。组件数量多的项目重新分析是个重活。并发开太高会把 CPU 和数据库打满开太低一次分析跑半小时。我的经验值是并发度设在 CPU 核数左右比较平衡超过这个数收益不明显。第四个是老项目的清理。跑了一年之后平台里往往积累了大量已经下线的服务和临时项目这些项目的组件记录还在被持续分析、持续产生告警。定期把确认下线的项目设为未激活能显著减少后台负担和告警噪音。7.3 备份与升级别把账本弄丢了平台里存的东西有个特点重建成本极高。项目、历史 SBOM、白名单里的判定结论、策略配置这些都是人工积累出来的容器可以重建这些丢了就没了。备份策略分两层。数据库按天全量转储这层是根本配置文件目录那个挂载到/data的卷定期打包里面有些运行期生成的密钥材料恢复时如果没有已签发的令牌会全部失效。升级时的动作顺序固定下来先停前端和 API 服务端转储数据库拉取目标版本镜像启动观察日志直到初始化完成最后验证一遍登录、项目列表、上传。跨大版本时同时要看升级说明里关于数据库迁移的注意事项有些版本要求先升到某个中间版本再继续硬跳会卡住。Dependency-Track 这套东西刚上手时容易觉得步骤多但真正的门槛不在部署而在于把它嵌进团队的日常——SBOM 要稳定地产生并上传策略要贴着实际情况调告警要有人接。我在实际推进时最有效的一个做法是先从两三个核心服务开始把从构建到告警的完整链路跑顺让团队先看到上周披露的那个漏洞我们在两小时内定位到了受影响的三个服务这样的实际效果再往其它项目铺开。反过来一上来就全量接入、全量告警大概率两周之后所有人都会把它当噪音源屏蔽掉。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表