4、SBOM生成工具(下):Trivy与cdxgen实战
上一讲我们聊了Syft和SPDX,这一讲继续深入。我个人习惯把Trivy和cdxgen放在一起讲,因为它们在实战中经常搭配使用——一个负责扫描已知漏洞,一个负责生成标准格式的SBOM。你想想看,如果只生成SBOM却不做漏洞关联,那这份清单的价值就大打折扣了。
4.1 使用Trivy生成SBOM
Trivy这工具,说白了就是个全能扫描器。很多人只知道它能扫容器镜像漏洞,其实它生成SBOM的能力也很强。我在项目中遇到过好几次,客户要求同时提供容器镜像的漏洞报告和SPDX格式的SBOM,Trivy一把梭就搞定了。
4.1.1 安装与基础用法
安装很简单,一条命令的事:
# macOS
brew install trivy
# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# Docker
docker pull aquasec/trivy:latest
生成SBOM的基本命令:
# 扫描镜像并生成CycloneDX格式的SBOM
trivy image --format cyclonedx --output result.cdx.json alpine:latest
# 生成SPDX格式
trivy image --format spdx-json --output result.spdx.json alpine:latest
# 扫描文件系统
trivy filesystem --format cyclonedx --output fs-sbom.json ./my-project
4.1.2 Trivy的SBOM生成原理
Trivy生成SBOM时,会先解析目标对象的包管理器信息。比如扫描一个Node.js项目,它会读取package-lock.json或yarn.lock;扫描Java项目,则解析pom.xml或build.gradle。然后它会把解析结果映射到CycloneDX或SPDX的组件模型上。
这里有个关键点——Trivy的SBOM生成和漏洞扫描是两套独立的引擎。生成SBOM时只做依赖解析,不做漏洞匹配。所以速度很快,一个中型Java项目大概几秒就能出结果。
--include-vuln参数。但我不建议这么做,因为SBOM应该保持纯净,漏洞信息可以单独关联。
4.2 Trivy与Syft的对比
很多学员问我:「Trivy和Syft到底选哪个?」我的回答是:看场景。下面这张表是我在实际项目中总结的对比:
| 维度 | Trivy | Syft |
|---|---|---|
| 核心定位 | 安全扫描器(漏洞+SBOM) | 专用SBOM生成器 |
| SBOM格式 | CycloneDX、SPDX | CycloneDX、SPDX、Syft自定义格式 |
| 依赖解析深度 | 中等(依赖锁文件) | 较深(支持更多包管理器) |
| 漏洞关联 | 内置漏洞数据库 | 无(需配合Grype) |
| 性能 | 较快(扫描+生成一体) | 极快(纯生成) |
| 适用场景 | CI/CD流水线中一站式扫描 | 需要精细控制SBOM内容的场景 |
举个例子。如果你在Jenkins流水线里既要生成SBOM又要做漏洞扫描,Trivy一步到位。但如果你需要把SBOM上传到某个平台做后续分析,而且对组件信息的完整性要求很高,Syft更合适——它支持的包管理器种类更多,解析也更细致。
4.3 使用cdxgen生成Java/JavaScript项目的SBOM
cdxgen这工具,说实话,在Java和JavaScript生态里比Trivy和Syft都更专业。它是专门为CycloneDX格式设计的生成器,对Maven、Gradle、npm、yarn这些包管理器的支持非常深入。
4.3.1 安装cdxgen
# 使用npm全局安装
npm install -g @cyclonedx/cdxgen
# 或者用Docker
docker pull ghcr.io/cyclonedx/cdxgen
# 验证安装
cdxgen --version
4.3.2 生成Java项目的SBOM
Java项目分Maven和Gradle两种,cdxgen都能处理:
# Maven项目
cdxgen -t java -o sbom-java.json .
# Gradle项目
cdxgen -t java -o sbom-gradle.json .
# 指定输出格式(默认CycloneDX JSON)
cdxgen -t java -o sbom.xml -f xml .
我在项目中遇到过一个问题:有些Maven项目用了私有仓库,cdxgen默认只解析pom.xml里的依赖声明,如果私有仓库里的包没有公开的POM文件,生成的SBOM会缺失这些组件的详细信息。解决办法是加--resolve-class参数:
cdxgen -t java --resolve-class -o sbom-full.json .
这个参数会让cdxgen去下载并解析JAR包里的pom.properties文件,信息会更完整。当然,代价是生成时间会变长。
4.3.3 生成JavaScript项目的SBOM
JavaScript项目相对简单,但要注意锁文件的选择:
# npm项目(推荐有package-lock.json)
cdxgen -t javascript -o sbom-npm.json .
# yarn项目
cdxgen -t javascript -o sbom-yarn.json .
# 指定类型为node.js
cdxgen -t node.js -o sbom-node.json .
package-lock.json的项目里直接跑cdxgen,结果生成的SBOM只有顶层依赖,所有传递依赖都丢了。后来我养成了习惯——生成SBOM前先检查锁文件是否存在。没有锁文件的项目,先跑npm install --package-lock-only生成锁文件再生成SBOM。
4.3.4 cdxgen的高级用法
cdxgen支持很多实用参数,我挑几个常用的:
# 生成包含漏洞信息的SBOM(需要配置NVD API Key)
cdxgen -t java --vuln -o sbom-vuln.json .
# 指定输出目录
cdxgen -t javascript --output-dir ./sbom-output .
# 生成BOML格式(更易读)
cdxgen -t java -f boml -o sbom.boml .
# 递归扫描子目录
cdxgen -t java --deep -o sbom-deep.json .
这里要特别提一下--vuln参数。它会把已知漏洞信息嵌入SBOM的vulnerabilities字段里。但说实话,我不太推荐在生产环境用这个功能——因为漏洞数据更新很快,今天生成的SBOM明天可能就过时了。我建议SBOM只记录组件清单,漏洞分析单独做。
4.4 三种工具的选型建议
最后总结一下我的选型逻辑:
- Trivy:适合CI/CD流水线,需要同时做漏洞扫描和SBOM生成的场景。一条命令搞定,省事。
- Syft:适合需要精细控制SBOM内容、或者要生成SPDX格式的场景。解析深度最好。
- cdxgen:Java和JavaScript项目的首选。对Maven/Gradle/npm/yarn的支持最专业,生成的CycloneDX格式最规范。
嗯,工具选型没有银弹。我自己的做法是:在项目的Makefile或package.json里配三个脚本,分别调用这三个工具,根据不同的交付要求选择不同的生成方式。这样既灵活又不会漏掉关键信息。