1. SBOM 基础概念:从一份“软件成分清单”说起
大家好,我是你们的讲师。今天咱们开始聊 SBOM——软件物料清单。这词儿听起来挺唬人,说白了就是一份“你家软件里都用了啥”的清单。
我记得几年前帮一家金融客户做安全审计,对方 CTO 拍着桌子问:“我们这产品到底引了多少开源组件?”没人答得上来。那时候我就意识到,没有 SBOM,你连自己家底都摸不清,还谈什么安全?
1.1 什么是 SBOM?
SBOM,全称 Software Bill of Materials。你可以把它想象成食品包装袋上的配料表。
买一包薯片,配料表会告诉你:土豆、植物油、食用盐、添加剂…… 每一行都清清楚楚。SBOM 就是软件的配料表——它列出了构成一个软件产品的所有“食材”:组件名称、版本号、依赖关系、许可证信息。
核心定义:SBOM 是一份结构化、机器可读的清单,记录了软件供应链中所有组件的元数据。它不是文档,是数据。
为什么需要它?你想想看,如果 Log4j 爆出漏洞,你第一反应是什么?——“我项目里用没用 Log4j?哪个版本?” 没有 SBOM,你得翻 pom.xml、package.json、Dockerfile…… 一个个找。有 SBOM,一行命令就能查出来。
我的经验: 我习惯把 SBOM 生成集成到 CI/CD 流水线里,每次构建自动生成一份。这样一旦有漏洞预警,5 分钟内就能定位受影响的服务。
1.2 SBOM 的组成要素
一份完整的 SBOM,至少包含四个核心要素。咱们一个一个说。
1.2.1 组件(Component)
组件就是软件里的每一个“零件”。它可以是:
- 一个开源库(比如 log4j-core)
- 一个第三方 SDK(比如 AWS SDK)
- 一个容器基础镜像(比如 alpine:3.18)
- 甚至是你自己写的内部模块
每个组件都需要一个唯一的标识符。常用的有:
- PURL(Package URL):比如
pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1 - CPE(Common Platform Enumeration):比如
cpe:2.3:a:apache:log4j:2.17.1
避坑指南: 我曾经遇到一个项目,SBOM 里只写了组件名,没写 PURL。结果漏洞扫描工具根本匹配不到 CVE。记住:标识符必须用标准格式,否则 SBOM 就是废纸。
1.2.2 版本(Version)
版本号是 SBOM 的灵魂。同一个组件,不同版本可能天差地别。log4j 2.14.1 有 RCE 漏洞,2.17.1 就修复了。没有版本号,你根本不知道风险有多大。
版本号通常遵循语义化版本规范(SemVer):主版本.次版本.补丁。但要注意,有些项目会用时间戳或 Git commit hash 做版本,SBOM 里也要如实记录。
1.2.3 依赖关系(Dependency)
组件不是孤立的。A 依赖 B,B 依赖 C,C 又依赖 D…… 这就是依赖树。SBOM 必须把这种关系说清楚。
举个例子:
my-app:1.0.0
├── spring-boot-starter-web:3.1.0
│ ├── spring-core:6.0.9
│ │ └── spring-jcl:6.0.9
│ └── tomcat-embed-core:10.1.12
└── log4j-core:2.17.1
└── log4j-api:2.17.1
为什么要记录依赖关系?因为漏洞会“传染”。如果 spring-core 有漏洞,所有间接依赖它的组件都受影响。没有依赖关系图,你根本算不清影响范围。
1.2.4 许可证(License)
许可证是法务部门最关心的。GPL、MIT、Apache 2.0、BSD…… 不同许可证对商用、分发、修改有不同要求。
我见过一个创业公司,用了 GPL 协议的库,结果产品被要求开源全部代码——差点倒闭。SBOM 里记录许可证,就是为了避免这种“许可证中毒”。
| 许可证 | 商用允许 | 修改后必须开源 | 典型组件 |
|---|---|---|---|
| MIT | ✅ | ❌ | React, jQuery |
| Apache 2.0 | ✅ | ❌ | Spring, Kubernetes |
| GPL v3 | ✅ | ✅ | Linux 内核部分模块 |
| BSD 3-Clause | ✅ | ❌ | Nginx, Redis |
1.3 SBOM 的格式标准
光有内容还不够,格式得统一。不然你拿 JSON,我用 XML,他写 YAML,根本没法互通。目前业界主流就两个标准:SPDX 和 CycloneDX。
1.3.1 SPDX
SPDX(Software Package Data Exchange)由 Linux 基金会维护。它诞生最早,2011 年就出了 1.0 版本。特点是:
- 许可证信息极其详细——SPDX 维护了一个庞大的许可证列表,每个许可证都有唯一 ID
- 文档结构严谨——适合合规审计场景
- 支持多种格式:RDF/XML、XLSX、JSON、YAML、Tag:Value
SPDX 2.3 是目前最广泛使用的版本。如果你做的是合规性要求高的项目(比如汽车、医疗),SPDX 是首选。
1.3.2 CycloneDX
CycloneDX 由 OWASP 维护。它更年轻(2017 年才出 1.0),但发展很快。特点是:
- 专为安全场景设计——原生支持漏洞引用、组件风险评分
- 轻量级——JSON 格式,解析快,适合 CI/CD 流水线
- 支持更多组件类型:容器、固件、SaaS、机器学习模型……
我个人习惯用 CycloneDX。为什么?因为它跟漏洞扫描工具配合得最好。OWASP Dependency-Check、Trivy、Grype 都原生支持 CycloneDX 格式。
| 特性 | SPDX | CycloneDX |
|---|---|---|
| 维护组织 | Linux 基金会 | OWASP |
| 首次发布 | 2011 | 2017 |
| 核心优势 | 许可证管理、合规审计 | 漏洞管理、安全集成 |
| 组件类型 | 软件包、文件 | 软件、容器、固件、SaaS |
| 漏洞支持 | 基础(外部引用) | 原生(漏洞对象、评分) |
| 推荐场景 | 法务合规、供应链披露 | DevSecOps、漏洞扫描 |
1.3.3 一个简单的 CycloneDX 示例
光说不练假把式。咱们看一段真实的 CycloneDX JSON:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"metadata": {
"timestamp": "2024-03-15T10:00:00Z",
"tools": [
{
"vendor": "OWASP",
"name": "CycloneDX Maven Plugin",
"version": "2.7.0"
}
],
"component": {
"type": "application",
"name": "my-app",
"version": "1.0.0"
}
},
"components": [
{
"type": "library",
"name": "log4j-core",
"version": "2.17.1",
"purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1",
"licenses": [
{
"license": {
"id": "Apache-2.0"
}
}
]
}
],
"dependencies": [
{
"ref": "pkg:maven/com.example/my-app@1.0.0",
"dependsOn": [
"pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1"
]
}
]
}
看到没?组件、版本、PURL、许可证、依赖关系,全在里面。机器读起来毫不费力。
1.4 SBOM 知识体系总览
为了让你对本章内容有个整体印象,我画了张图:
这张图把 SBOM 的核心脉络串起来了。左边是“有什么”,右边是“怎么写”,底部是“为什么做”。
我的建议: 刚开始接触 SBOM,别纠结选 SPDX 还是 CycloneDX。先跑起来,生成一份看看长什么样。我当年就是从 mvn org.cyclonedx:cyclonedx-maven-plugin:makeBom 这条命令开始的。