news 2026/10/1 16:36:39

Dependency-Track实战:基于SBOM的持续依赖漏洞治理与CI/CD集成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dependency-Track实战:基于SBOM的持续依赖漏洞治理与CI/CD集成

1. 为什么是Dependency-Track:从一次性扫描到持续治理

先说个真实场景。上个月有个研发团队找到我,说他们上线前被安全部门卡住了,原因是第三方依赖库里的漏洞报告一直无法闭环——OWASP Dependency-Check扫出来的问题没人跟进,下次扫描又全部冒出来,开发说“我改了这版依赖”,安全说“报告里没体现”,最后只能靠截图和Excel表格来回拉扯。

我给他们部署了一套Dependency-Track,两周后这个问题基本消停了。Dependency-Track是一个开源的软件组件分析平台,核心思路非常直接:它不站在“扫描一次”的角度工作,而是以软件物料清单(SBOM)为中心,帮你做持续性的安全治理。开发把当前版本的依赖清单交上去,平台负责入库、关联漏洞库、持续监控新披露的漏洞、跟踪审计状态,并把结果通知给相关人员。

和常见依赖扫描工具做个对比,差异就很明显:

对比项Dependency-CheckDependency-Track
工作方式构建时扫描,出报告即结束平台化持续分析,记录每次快照
漏洞跟踪无状态,下次扫描重新开始有状态,标记审计结论、修复进度
数据输入自动探测项目依赖接收SBOM、自动检测,也可手工管理
团队协作单机报告多用户、权限、通知、策略管理
生态扩展插件形式REST API + 平台级集成

一句话概括:Dependency-Check是“安全体检”,Dependency-Track是“健康档案”。如果你的团队只是偶尔看一下依赖有没有问题,前者够用;如果你需要应对合规审计、漏洞闭环、供应链安全治理,那Dependency-Track这个层级才是真正需要的。

这篇文章就基于我实际部署和使用的经历,把从环境搭建、CI/CD接入、SBOM分析遇到的核心问题到团队落地经验一次性讲透。适合正在选型或已经部署但用不起来的同学。

2. 从零搭建:Docker Compose部署与初始配置

2.1 部署方式选型

Dependency-Track官方提供了多种部署方式,包括Docker Compose、Kubernetes Helm Chart、以及传统的WAR包部署。个人建议直接上Docker Compose,理由有三点:

  1. 官方维护了一套配置好的多容器编排,前端(前端服务)、API服务、数据库服务的关系已经理清,不需要自己去折腾环境变量对接。
  2. 升级方便,拉新镜像重启即可,备份也简单。
  3. 对大多数团队来说,单节点部署完全够用——它不需要ES那套复杂组件,默认用的数据库是内置的H2,也可以切换成PostgreSQL或SQL Server。

下面是生产环境推荐的结构图(文字版):浏览器请求通过Nginx进入前端容器,前端容器通过反向代理访问API服务,API服务连接数据库和各类漏洞数据源。所有组件通过docker-compose统一管理。

2.2 实际部署步骤

部署前先看看机器配置。官方建议的最低配置是4核8GB内存,但我强烈建议给8核16GB以上。很多人忽视了内存问题,后面同步NVD漏洞库时直接OutOfMemory,这是最常踩的坑,后面专门说。

部署过程分四步:

第一步,准备docker-compose.yml。官方仓库里有现成的(docker-compose.yml),也可以自己写一个精简版本。我用的配置类似这样:

version: '3' services: dtrack-frontend: image: dependencytrack/frontend:4.11.6 restart: unless-stopped depends_on: - dtrack-apiserver ports: - "8080:8080" dtrack-apiserver: image: dependencytrack/apiserver:4.11.6 restart: unless-stopped environment: - ALPINE_DATABASE_MODE=external - ALPINE_DATABASE_URL=jdbc:postgresql://dtrack-db:5432/dtrack - ALPINE_DATABASE_DRIVER=org.postgresql.Driver - ALPINE_DATABASE_USERNAME=dtrack - ALPINE_DATABASE_PASSWORD=change_me_to_a_strong_password - ALPINE_HTTP_PORT=8081 depends_on: - dtrack-db volumes: - dtrack-data:/data dtrack-db: image: postgres:16-alpine restart: unless-stopped environment: - POSTGRES_DB=dtrack - POSTGRES_USER=dtrack - POSTGRES_PASSWORD=change_me_to_a_strong_password volumes: - dtrack-db-data:/var/lib/postgresql/data volumes: dtrack-data: dtrack-db-data:

第二步,启动容器:

docker-compose up -d

第三步,打开前端页面,地址是http://你的服务器IP:8080,初始账号是admin,密码是admin。登录后系统会强制要求修改密码,这是官方的安全策略,不要跳过。

第四步,强烈建议开启TOTP双因素认证。Dependency-Track支持基于时间的一次性验证码,在个人账号设置里扫描二维码绑定即可。安全团队的对账审计会要求账号必须有双因素,提前做好能省不少事。

2.3 初始配置的关键细节

有几个配置项在部署的时候就要想清楚,不然后面改起来麻烦:

一是数据库密码。不要在默认compose文件上直接跑,改成强密码是底线。如果是在云服务器上部署,建议把数据库端口完全关闭,只允许内部网络访问API容器。

二是API服务的端口映射。前端默认8080,API服务默认8081。前端页面访问的不是API端口,它自己会做代理,所以正常使用只需暴露8080。但后面做CI/CD集成时,API请求直接走8081会更清晰,建议在安全组里只允许公司内部IP访问8081。

三是数据目录的持久化。API容器里的/data目录存了漏洞数据库索引、上传的SBOM文件、任务日志,数据库容器里的数据文件存了所有业务数据。这两个volume一定要保留好,容器没了可以重建,数据没了就很被动。生产环境建议用云盘或NFS,避免宿主机磁盘损坏导致数据丢失。

四是升级策略。Dependency-Track的版本迭代不算慢,但其间涉及数据库schema迁移,升级前务必做一次完整备份。它没有自动备份功能,我是写了一个cron脚本,每天凌晨用docker exec导出PostgreSQL的数据,保留最近14天的备份文件,实测恢复过两次,都很顺利。

3. 接入研发流程:CI/CD集成与API调用

3.1 设计思路:生成SBOM,而不是直接扫描

很多人第一次用Dependency-Track,第一反应是“它怎么像Dependency-Check那样扫我项目?”这里有个关键的设计理念需要转变:Dependency-Track的核心输入是SBOM,而不是项目源码。它不直接扫描代码,它消费的是描述“我这版本用了哪些组件、哪些版本”的结构化清单。

把SBOM生成和漏洞分析解耦的最大好处是什么?生成SBOM是编译期的事情,速度快、反馈及时;漏洞分析是平台侧的事情,可以后台慢慢跑,不会拖慢构建流水线,也不会因为NVD同步慢而让开发等结果。

所以在CI/CD里的正确姿势是:

  1. 构建阶段生成SBOM(格式选CycloneDX JSON)。
  2. 调用Dependency-Track API上传SBOM,绑定项目名称和版本。
  3. 平台异步处理,分析结果通过Webhook或后续查询反馈,也可以在发布前通过策略检查决定是否阻断。

3.2 生成SBOM的工具选型

不同技术栈生成SBOM的工具不一样,我这里列几个亲测好用的:

技术栈推荐工具说明
Java/MavenCycloneDX Maven Plugin执行mvn cyclonedx:makeAggregateBom生成整个多模块项目的完整清单
Java/GradleCycloneDX Gradle Plugin用法类似,能处理依赖约束和BOM引入
Node.js@cyclonedx/cyclonedx-npm支持读取package-lock.json生成SBOM
PythonCycloneDX Python库或pip-audit的SBOM输出虚拟环境里直接生成
通用容器镜像Syft(Anchore出品)一条命令扫描镜像,输出CycloneDX JSON,支持各种镜像格式

Syft几乎成了我团队的标准配置,因为现在服务大多是容器化部署,直接扫镜像最省事,不用管内部是什么语言:

syft packages your-registry/app:1.2.3 -o cyclonedx-json > sbom.json

3.3 在GitLab CI里集成

以GitLab CI为例,一个完整的阶段可以这样设计。dependency-track阶段负责生成和上报SBOM,security-check阶段在发布前做策略判定:

generate-sbom: stage: dependency-track image: anchore/syft:latest script: - syft packages ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG:-latest} -o cyclonedx-json > sbom.json artifacts: paths: - sbom.json expire_in: 1 week only: - tags upload-sbom: stage: dependency-track image: alpine:latest variables: DEPENDENCY_TRACK_URL: "http://dtrack.internal.example.com/api" DEPENDENCY_TRACK_API_KEY: "$DTRACK_API_KEY" script: - apk add --no-cache curl jq - | curl -sS -X "POST" "${DEPENDENCY_TRACK_URL}/v1/bom" -H "X-Api-Key: ${DEPENDENCY_TRACK_API_KEY}" -H "Content-Type: application/json" -d "{ \"projectName\": \"${CI_PROJECT_NAME}\", \"projectVersion\": \"${CI_COMMIT_TAG}\", \"bom\": \"$(cat sbom.json | base64 -w0)\", \"autoCreate\": true }" only: - tags

这里有两个容易忽略的细节:

  • bom字段需要base64编码,不是直接传JSON。很多人第一次调API报400就是死在这个地方。
  • autoCreate设置为true后,平台发现项目不存在会自动创建,省去手工建项目的步骤。但如果项目已经有固定归属团队,建议还是预先创建好,避免一人一个命名风格搞出很多重复项目。

上传之后,平台返回一串token,可以用来查询分析状态:

curl -sS -X "GET" "${DEPENDENCY_TRACK_URL}/v1/bom/token/你的token" -H "X-Api-Key: ${DEPENDENCY_TRACK_API_KEY}" | jq .status

返回PROCESSING表示还没解析完,COMPLETED表示可以去看结果了。

3.4 API Key的管理权限

Dependency-Track的API Key分三种层级:管理员、发布经理、观察者。CI/CD里用的Key建议单独创建一个观察者或发布经理角色的Key,不要直接拿管理员Key到处用。在“管理-访问管理-团队”里新建团队,赋权后生成Key,Key本身很长,建议放到CI/CD的变量里统一管理,不要写死在代码仓库。

关于projectName的设计,我的建议是:应用名留CI_PROJECT_NAME即可,版本号用CI_COMMIT_TAG或构建号,这样每次发版都会形成一条独立的快照记录。以后安全团队说“v1.2.3这个版本有高危漏洞”,你在平台上点一下就能看到当时的完整依赖情况,这就是审计追溯的价值。

4. SBOM上传与漏洞分析的正确姿势

4.1 项目、版本与SBOM的对应关系

先理解Dependency-Track的数据模型:项目(Project)是顶层对象,一个项目下有多个版本(Project Version),每个版本关联一份或多份SBOM快照。漏洞分析的结果是挂在项目版本下面的。

所以正确用法不是每次上传都建新项目,而是按“应用名+版本号”上报。这样同一个应用的历史漏洞记录都在一个项目下,可以按版本切换查看。

我见过不少团队把每个构建版本都建一个独立项目,最后平台上一堆同名项目,看不到时间线,审计状态也串了。这就是数据模型没理解到位。

4.2 漏洞数据源与同步管理

平台能分析出漏洞,核心在于它聚合了多个漏洞数据源。管理界面(Administration-System Configuration)里可以配置数据源,包括:

  • NVD(美国国家漏洞数据库):最基础的数据源,官方接口有速率限制,第一次同步特别慢,要耐心等。
  • GitHub Advisories:开源生态的漏洞公告,覆盖很及时,但需要配置GitHub Token才能拉取。
  • OSV:谷歌维护的开源漏洞数据库,覆盖面广,不少新披露的漏洞第一时间在这里出现。
  • CISA KEV:已知被利用漏洞目录,用于优先级排序。

这些数据源不是一次性拉完就结束了,平台会按固定周期增量更新。默认的同步周期可以保留,生产环境建议NVD每天同步一次,GitHub Advisories每6小时一次,这样新漏洞披露到平台可查的窗口期不会太长。

同步状态可以在后台任务面板里看,如果哪个数据源一直失败,通常是网络代理问题或者Token失效,排查思路很直接:先看API服务日志里对应任务的报错,再确认出网是否有白名单限制。

4.3 分析页面怎么用

上传SBOM并完成分析后,主要看这几个页面:

  • 项目视图:选中项目版本,能看到本次SBOM包含的组件总数、漏洞数、策略违例数。按风险等级(严重/高危/中危/低危)分布也在这里展示。
  • 组件视图:点进某个组件,能看到它涉及的漏洞列表、CVE详情、CVSS评分、EPSS分数(利用概率评分),以及该组件在哪些项目里被使用。
  • 漏洞视图:从漏洞维度看影响面,知道“这个CVE影响了我们哪几个项目”,用于评估紧急程度。
  • 策略违例视图:如果你配置了策略(Policy),这里会显示哪些组件触发了限制性规则。

审计操作就在漏洞视图里做。打开一个漏洞,右侧面板里可以设置审计状态:

审计状态含义使用场景
存在(Vulnerable)确认受影响,需要修复默认状态
不受影响(Not Affected)分析后确认实际不受影响例如组件虽然匹配CVE但代码路径未用到
误报(False Positive)确认不是真实漏洞例如CVE实际影响的是另一个语言生态的同名包
已修复(Resolved)该版本已验证修复升级依赖后确认不再存在

加上注释后,审计状态会被记录,下次再有人看这个漏洞时就能看到结论。这就是闭环:开发说“这个组件实际没用到危险函数”,安全同学同意后标记为误报并附上分析说明,以后重复扫描不会再次报警。

实际操作下来,比较费时间的是刚接入平台第一周,旧项目的存量漏洞需要批量审计。好在平台支持多选组件后批量设置审计状态并添加统一注释,不需要逐条点。

4.4 保险起见:利用策略做发布防线

Dependency-Track的策略(Policy)能力值得单独说明。策略可以基于漏洞严重程度、组件名称、组件版本、CISA KEV标记等条件来定义“违规”。例如:

  • 策略A:存在CISA KEV标记漏洞的组件,不允许发布。
  • 策略B:存在CVSS评分9.0以上的严重漏洞,不允许发布。
  • 策略C:禁止使用已EOL的组件版本。

配置策略后,CI里调用“策略违例查询”接口,就能拿到当前项目是否有阻断级的违规项,再决定流水线是否放行:

curl -sS -X "GET" "${DEPENDENCY_TRACK_URL}/v1/project/lookup?name=项目名&version=版本号" -H "X-Api-Key: ${DEPENDENCY_TRACK_API_KEY}" | jq -r '.uuid'

拿到UUID后查询违例:

curl -sS -X "GET" "${DEPENDENCY_TRACK_URL}/v1/violation/project/项目UUID" -H "X-Api-Key: ${DEPENDENCY_TRACK_API_KEY}" | jq '[.[] | select(.type == "VULNERABILITY" and .severity == "CRITICAL")] | length'

返回数量大于0就阻断。有的团队担心“阻断发布会拖慢交付”,我的建议是:刚开始策略先做成“审计视线”不加阻断,跑两个迭代看误报率,稳定后再从最关键的项目开启阻断。安全建设不是一次性到位,而是逐步收紧。

5. 日常运维中最容易翻车的几个点

5.1 内存不足导致NVD同步失败

这是Dependency-Track部署后最常见的故障。NVD全量数据同步时,API服务需要把大量CVE数据写入本地索引,如果JVM堆内存分配不够,直接抛出OutOfMemoryError,后台任务显示失败,前端页面可能出现组件漏洞信息缺失。

排查思路是:先看容器日志里有没有java.lang.OutOfMemoryError: Java heap space,如果有,基本可以锁定。解决办法有两个方向:一是给Docker分配更大内存,把宿主机内存从8GB升到16GB,同时确认API容器的JVM参数允许大堆内存;二是在/data目录下合理配置索引存储,不要让它和系统其他服务抢磁盘。

我给一个小团队的部署建议是:如果公司只是做几十个项目的依赖治理,单机16GB内存绰绰有余;如果上百个项目、SBOM上传频率高,考虑把所有组件迁到PostgreSQL、API服务独立部署、数据库交给云厂商托管那一套。

5.2 同步NVD走了代理,Token失效

很多公司内网服务器不能直连外网,NVD同步必须走代理。Dependency-Track本身没有在UI里直接配置代理的地方,需要在API服务的启动参数里设:

export JAVA_OPTIONS="-Dhttps.proxyHost=代理IP -Dhttps.proxyPort=代理端口"

更隐蔽的问题是GitHub Token失效。平台每次同步GitHub Advisories,需要有效的Token。Token过期后后台任务报401,但UI上的“上次同步时间”看起来还正常,容易忽略。运维上我建议用公司统一的机器账号Token,加上告警:每天检查同步任务日志里有没有401/403报错,有就通知安全负责人。

5.3 上传SBOM后漏洞数量异常

可能出现“上传的SBOM明明很小,但平台分析出的组件数量翻了几倍”的情况。这种一般是SBOM里的components字段嵌套了元组件和子组件,比如Java的BOM引入传递性依赖,平台在解析CycloneDX时会把所有传递依赖全部展开。

这不一定是问题,但会导致审计工作量变大。如果业务上只关心直接依赖,可以在生成SBOM时关闭传递依赖解析(以CycloneDX Maven插件为例,设置includeTransitive为false),或者在上传前用jq过滤掉非直接依赖。权衡下来,我是建议保留传递依赖,因为不少高危漏洞恰恰藏在二级依赖里。

5.4 前端页面加载慢、卡顿

前端大量数据的表格渲染,在项目组件数量过万时确实会卡。除了清理浏览器的缓存,更有效的是开启API服务的压缩功能,在Nginx层配置:

gzip on; gzip_min_length 1k; gzip_types application/json application/javascript text/css image/svg+xml;

另一个常见原因是平台自动刷新漏洞视图,每次切换项目版本都会重新拉全量数据。数据量很大的项目,建议通过左侧的过滤器缩小范围,不要一上来就全量加载“所有项目”。

5.5 备份和恢复

备份这事儿嘴上说再多不如实际演练一次。我是用cron脚本每天备份PostgreSQL数据库,具体流程是:

docker exec dtrack-db pg_dump -U dtrack dtrack > dtrack_$(date +%Y%m%d).sql

注意/data目录下的索引文件不备份问题也不大,但数据库必须备份。恢复的时候,先把API和前端容器停掉,启动一个临时PostgreSQL容器导入SQL,再启动业务容器。整个过程我实测过,10分钟内能完成。

有一种情况比较麻烦:数据库备份是在业务还在运行的时候导出的,可能要恢复的瞬间有未提交事务,不过Dependency-Track不会有那么高写入频率,所以只要不是正在大量上传SBOM的窗口,正常备份恢复是可靠的。

6. 团队落地推广:从部署到真正被用起来

工具部署好只是第一步,真正难的是让团队成员接受并养成习惯。我在这几个项目里总结了一些适用经验。

6.1 从两个项目试点切入

不要试图一次性把所有项目都接入Dependency-Track。我的习惯是选两个代表性项目试点:一个是对外提供服务的核心应用,一个是内部工具类应用。试点时间定两个迭代周期,目标不是看漏洞数量,而是验证:

  1. CI里集成SBOM上传是否稳定。
  2. 开发人员能否看懂漏洞审计页面。
  3. 安全团队能否接收通知并处理告警。

试点通过后再批量接入其他项目,推广阻力会小很多。

6.2 通知规则要分层配置

Dependency-Track的通知机制支持通过Webhook、邮件等方式推送漏洞信息。这里最忌讳的是“所有漏洞都通知所有人”,那样很快就被当做垃圾消息忽略了。

我的配置经验是:

通知对象漏洞级别频率
应用负责人高危/严重实时Webhook到企业微信/钉钉群
开发团队中危日报汇总
安全团队全部实时或日报,视团队人力而定
管理层严重漏洞+无法修复的漏洞周报

细分下来,通知数量可控,也能保证漏洞出现后有人响应。

6.3 权限要分角色

默认的admin账号不建议给所有人用。Dependency-Track基于角色的访问控制支持自定义角色和映射。落地时我是这样分的:

  • 安全团队:管理员权限,负责配置数据源、策略、分析审计。
  • 研发负责人:项目的查看权限+审计权限。
  • 普通开发人员:查看权限,可以标记误报,但不能修改策略配置。

这样既保证开发能参与漏洞闭环,又避免误操作把全局策略改坏。

6.4 与Jira等工单系统联动

漏洞闭环最怕“看了就没了”。Dependency-Track支持Webhook触发,配合自动化脚本把高危漏洞自动创建Jira工单,分配给对应应用负责人,工单关联漏洞详情,修复后在平台上反查确认。这个联动逻辑不复杂,本质是一个接收Webhook的小服务,但对流程闭环的意义非常大。没有这类自动化之前,漏洞记录和安全运营割裂,有了联动,KPI就变成“工单关闭率”了。

6.5 定期做数据治理和报告

运行一两个月后,平台里会有大量项目、组件和审计记录。项目如果废弃了,可以归档;组件如果长时间没有版本更新,要关注一下是不是没人维护。建议安全团队每月拉一次全量报告,看三个指标:

  1. 高危漏洞数量环比变化。
  2. 平均修复时间(从漏洞发现到标记已修复的天数)。
  3. 审计率(已审计漏洞占全部漏洞的比例)。

审计率的价值容易被忽略。如果审计率低,说明开发和安全没有真正在用这个平台,漏洞都可能没被点开过;审计率高,说明流程是活的,有安全运营在里面。

Dependency-Track不是装了就能“自动解决安全合规”的银弹,但它确实把供应链依赖治理这件事从“手工扫码发邮件”推进到了“平台化持续运营”的层面。按这套方法部署、接入、运维、推广下来,团队能真正把这套系统用起来,而不是让它沦为摆设。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 16:34:53

YOLO山体落石检测实战:小目标识别与边缘部署全链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 16:34:46

Darknet版YOLOv3火焰烟雾检测:小样本训练与部署实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 16:33:38

Screen会话持久化:Autodl远程深度学习训练防断线指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 16:33:12

MSE分解实战:用Bias-Variance诊断模型偏差与波动

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 16:33:11

cmd下Python虚拟环境配置:venv/conda/uv选型与激活原理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华