3. SBOM标准与格式
聊到SBOM,绕不开的就是格式问题。你想想看,如果大家各自用不同的方言描述同一个软件成分,那交换起来得多费劲?所以标准化就成了关键。目前业界主流的三种格式,我这些年都深度用过,各有各的脾气。今天咱们就掰开揉碎了聊聊。
3.1 SPDX格式详解
SPDX(Software Package Data Exchange)是Linux基金会牵头搞的,历史最久,生态也最成熟。我个人习惯把它看作是SBOM界的“普通话”——规范、严谨、覆盖面广。
SPDX的核心思路是用一个统一的文档来描述软件包、许可证、版权信息和文件级别的引用关系。它的文档结构非常清晰,主要包含以下几个部分:
- 文档创建信息:谁创建的、什么时候、用什么工具。
- 包信息:包名、版本、下载位置、校验和(SHA1/SHA256)。
- 文件信息:每个文件的校验和、文件类型、版权信息。
- 许可证信息:声明的许可证、实际检测到的许可证、许可证注释。
- 关系信息:包与包之间的依赖关系(DEPENDS_ON、CONTAINS等)。
我在项目中遇到过最头疼的事,就是供应商给的固件里混了一堆GPL代码,但他们的SPDX文档里只字未提。后来我们强制要求所有上游组件必须附带SPDX 2.2格式的SBOM,才把这个问题堵住。
SPDX 2.3 版本的一个关键改进:引入了“安全参考”字段,可以直接关联CVE编号。这意味着你可以从SBOM直接跳转到漏洞库,省去了手动查表的功夫。
下面是一个简化的SPDX示例,展示了一个固件包的基本描述:
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: firmware-v3.2.1
Creator: Tool: sbom-tool-1.0
Created: 2024-03-15T10:00:00Z
##### Package: firmware-core
PackageName: firmware-core
SPDXID: SPDXRef-Package-firmware-core
PackageVersion: 3.2.1
PackageDownloadLocation: git+https://git.example.com/firmware-core.git
PackageChecksum: SHA256: abc123...
PackageLicenseConcluded: GPL-2.0-only AND MIT
##### Relationship
Relationship: SPDXRef-Package-firmware-core DEPENDS_ON SPDXRef-Package-libcrypto
我的小技巧:SPDX的校验和字段一定要填。我曾经见过一个SBOM,所有校验和都是空的,那这个SBOM基本等于废纸——你没法验证你拿到的二进制是不是就是文档里描述的那个。
3.2 CycloneDX格式详解
CycloneDX是OWASP社区推的格式,一开始就冲着安全场景去的。说白了,它比SPDX更“轻量”,更专注于漏洞管理和依赖分析。如果你主要关心“这个组件有没有漏洞”,那CycloneDX用起来会更顺手。
CycloneDX的JSON结构非常紧凑,核心字段包括:
- bomFormat:固定为"CycloneDX"。
- specVersion:格式版本号,目前主流是1.5。
- components:组件列表,每个组件包含name、version、purl、licenses等。
- dependencies:依赖关系图,用ref字段关联。
- vulnerabilities:直接嵌入漏洞信息,包括CVE、CVSS评分、修复建议。
我记得有一次做固件安全审计,客户要求我们提供所有第三方库的漏洞清单。如果用SPDX,我得额外写脚本去查CVE库。但CycloneDX直接支持在SBOM里内嵌漏洞数据,一条命令就搞定了。嗯,这就是它设计上的优势。
注意:CycloneDX的purl(Package URL)字段非常关键。它像是一个组件的“身份证”,格式为 pkg:type/namespace/name@version。如果purl写错了,自动化的漏洞匹配工具就会认不出来。我见过有人把purl的斜杠方向写反,结果整个依赖分析全乱了。
一个典型的CycloneDX片段长这样:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"components": [
{
"type": "library",
"name": "libcurl",
"version": "7.88.1",
"purl": "pkg:generic/libcurl@7.88.1",
"licenses": [
{
"license": {
"id": "MIT"
}
}
]
}
],
"dependencies": [
{
"ref": "pkg:generic/firmware-core@3.2.1",
"dependsOn": [
"pkg:generic/libcurl@7.88.1"
]
}
]
}
3.3 SWID标签介绍
SWID(Software Identification)标签是ISO/IEC 19770-2标准,跟前面两个不太一样。它更侧重于软件安装后的识别和管理,说白了就是“装到机器上了,我怎么知道它是谁”。
SWID标签通常以XML格式存在,嵌入在安装包或固件镜像里。它的核心元素包括:
- SoftwareIdentity:根元素,包含name、version、tagId。
- Entity:软件发布者信息。
- Evidence:安装证据,比如文件路径、注册表项。
- Payload:软件包含的文件清单。
我在做固件供应链管理时,发现SWID标签在Windows生态里用得特别多。微软的很多组件都自带SWID标签,方便企业做资产盘点。但在嵌入式Linux固件里,SWID的普及率远不如SPDX和CycloneDX。
SWID的一个独特优势:它支持“证据”字段,可以记录软件安装后留下的痕迹。这对于固件运行时验证非常有用——你可以通过检查SWID标签里的文件哈希,确认固件没有被篡改。
3.4 三种格式的对比与选型
好了,三种格式都介绍完了。你可能会问:“那我到底该用哪个?” 别急,我整理了一张对比表,你看完心里就有数了。
| 维度 | SPDX | CycloneDX | SWID |
|---|---|---|---|
| 标准化组织 | Linux基金会 | OWASP | ISO/IEC |
| 核心用途 | 许可证合规 + 成分披露 | 漏洞管理 + 依赖分析 | 软件安装识别 + 资产盘点 |
| 数据格式 | Tag/Value、JSON、RDF/XML | JSON、XML | XML |
| 漏洞支持 | 2.3版本开始支持 | 原生支持,可内嵌CVE | 弱,需外部关联 |
| 依赖关系 | 支持,关系类型丰富 | 支持,图结构清晰 | 有限,主要描述包含关系 |
| 工具生态 | 非常成熟,FOSSology等 | 快速增长,OWASP工具链 | 较封闭,厂商绑定多 |
| 固件适用性 | 高,适合复杂许可证场景 | 高,适合安全审计场景 | 中,适合Windows/商业软件 |
选型上,我个人的建议是这样的:
- 如果你的主要痛点是许可证合规(比如怕GPL污染),选SPDX。它的许可证字段最完善,法律团队也认。
- 如果你的主要痛点是漏洞管理(比如每天要查CVE),选CycloneDX。它原生支持漏洞内嵌,自动化程度高。
- 如果你在做企业资产盘点,或者你的固件跑在Windows IoT上,可以考虑SWID。但说实话,在嵌入式固件领域,SWID的生态还不够强。
我的实战经验:别死磕一种格式。我在一个项目里同时用了SPDX和CycloneDX——SPDX给法务看,CycloneDX给安全团队用。两边都满意,何乐而不为?
最后,我用一张图来总结这三种格式在固件生命周期中的定位:
这张图很直观地展示了:SPDX和CycloneDX在固件开发到运维的整个链条上都有覆盖,而SWID更偏向部署后的场景。我个人在固件项目里,基本是SPDX打底、CycloneDX做安全增强,SWID只在客户有明确要求时才加。