3、SBOM格式解析:SPDX与CycloneDX深度拆解
说到SBOM的格式,市面上主流的就两个——SPDX和CycloneDX。我刚开始接触SBOM的时候,也被这两个格式搞得有点晕。后来在几个实际项目里反复折腾,才真正摸清了它们的脾气。今天我就把这两套格式掰开揉碎了讲给你听。
说白了,SPDX和CycloneDX就像两种不同的语言,都能描述软件供应链,但语法和侧重点不一样。你想想看,选错了格式,后面解析、对比、生成报告都会很痛苦。所以这一节,咱们把它们的细节都过一遍。
3.1 SPDX格式详解
SPDX(Software Package Data Exchange)是Linux基金会旗下的标准。我记得最早接触它是在2019年,那时候公司要做开源合规审计,SPDX几乎是唯一的选择。它的核心优势在于——对许可证和版权的描述非常精细。
3.1.1 SPDX JSON格式
JSON格式是我个人最常用的。结构清晰,解析方便,几乎所有编程语言都能直接处理。一个典型的SPDX JSON文档长这样:
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "my-app-sbom",
"creationInfo": {
"created": "2024-01-15T10:00:00Z",
"creators": [
"Tool: sbom-tool-1.0",
"Organization: Example Corp"
]
},
"packages": [
{
"SPDXID": "SPDXRef-Package-log4j-2.17.1",
"name": "log4j-core",
"versionInfo": "2.17.1",
"supplier": "Organization: Apache Software Foundation",
"licenseConcluded": "Apache-2.0",
"licenseDeclared": "Apache-2.0",
"copyrightText": "Copyright 2023 The Apache Software Foundation",
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "a1b2c3d4e5f6..."
}
],
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceType": "cpe23Type",
"referenceLocator": "cpe:2.3:a:apache:log4j:2.17.1"
}
]
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-Package-log4j-2.17.1",
"relationshipType": "DESCRIBES"
}
]
}
这里有几个关键字段我得提醒你注意:
- spdxVersion:目前最新是2.3,3.0还在草案阶段。我建议你直接用2.3,工具链支持最成熟。
- licenseConcluded vs licenseDeclared:前者是经过人工审核后确定的许可证,后者是组件自身声明的。这两个字段不一致时,说明可能有许可证冲突。
- externalRefs:这个字段特别重要,它关联了CPE或PURL,是后续做漏洞匹配的关键。
3.1.2 SPDX Tag-value格式
Tag-value是SPDX最早支持的格式,也是它的"原生"格式。说实话,这种格式现在用得越来越少了,但有些老工具和合规审计系统还在用。它的样子是这样的:
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: my-app-sbom
Creator: Tool: sbom-tool-1.0
Creator: Organization: Example Corp
Created: 2024-01-15T10:00:00Z
##### Package: log4j-core
PackageName: log4j-core
SPDXID: SPDXRef-Package-log4j-2.17.1
PackageVersion: 2.17.1
PackageSupplier: Organization: Apache Software Foundation
PackageLicenseConcluded: Apache-2.0
PackageLicenseDeclared: Apache-2.0
PackageCopyrightText: Copyright 2023 The Apache Software Foundation
PackageChecksum: SHA256: a1b2c3d4e5f6...
ExternalRef: SECURITY cpe23Type cpe:2.3:a:apache:log4j:2.17.1
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-log4j-2.17.1
嗯,这里要注意。Tag-value格式的解析比JSON麻烦很多。它没有嵌套结构,全靠前缀和缩进来表达层级关系。我建议你只在以下场景使用它:
- 对接老旧的合规审计系统,它们只认Tag-value
- 需要人工阅读和编辑SBOM文件(Tag-value确实比JSON更易读)
- 带宽或存储受限的环境(Tag-value体积更小)
3.2 CycloneDX格式详解
CycloneDX是OWASP社区推动的标准。它的设计初衷就是解决软件供应链安全问题。我个人觉得,如果你主要关注漏洞扫描和依赖管理,CycloneDX比SPDX更顺手。
3.2.1 CycloneDX JSON格式
CycloneDX JSON的结构比SPDX更紧凑。它把组件、依赖、漏洞信息都组织得很清晰。来看一个例子:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
"version": 1,
"metadata": {
"timestamp": "2024-01-15T10:00:00Z",
"tools": [
{
"vendor": "Example Corp",
"name": "sbom-tool",
"version": "1.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"
}
}
],
"hashes": [
{
"alg": "SHA-256",
"content": "a1b2c3d4e5f6..."
}
]
}
],
"dependencies": [
{
"ref": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1",
"dependsOn": [
"pkg:maven/org.apache.logging.log4j/log4j-api@2.17.1"
]
}
]
}
你发现没有?CycloneDX用purl(Package URL)来标识组件,而不是CPE。这是一个很大的优势。PURL的格式更统一,解析起来也更简单。而且CycloneDX原生就支持dependencies字段,可以直接表达组件之间的依赖关系。
3.2.2 CycloneDX XML格式
XML格式在CycloneDX中也很常见,尤其是在企业级Java生态里。它的结构和JSON是对应的:
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.5"
serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"
version="1">
<metadata>
<timestamp>2024-01-15T10:00:00Z</timestamp>
<tools>
<tool>
<vendor>Example Corp</vendor>
<name>sbom-tool</name>
<version>1.0</version>
</tool>
</tools>
</metadata>
<components>
<component type="library">
<name>log4j-core</name>
<version>2.17.1</version>
<purl>pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1</purl>
<licenses>
<license>
<id>Apache-2.0</id>
</license>
</licenses>
<hashes>
<hash alg="SHA-256">a1b2c3d4e5f6...</hash>
</hashes>
</component>
</components>
<dependencies>
<dependency ref="pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1">
<dependency ref="pkg:maven/org.apache.logging.log4j/log4j-api@2.17.1"/>
</dependency>
</dependencies>
</bom>
XML格式的好处是——有严格的Schema定义,可以做XSD校验。如果你需要保证SBOM的结构完整性,XML是更好的选择。但缺点也很明显:文件体积大,解析速度慢。
3.3 格式对比与选型建议
好了,两种格式都讲完了。咱们来做个横向对比。我整理了一张表,你可以直接拿去用:
| 对比维度 | SPDX | CycloneDX |
|---|---|---|
| 主导组织 | Linux基金会 | OWASP |
| 核心关注点 | 许可证合规、版权信息 | 安全漏洞、依赖关系 |
| 组件标识 | CPE + 自定义SPDXID | PURL(原生支持) |
| 依赖关系表达 | 通过Relationships字段间接表达 | 原生dependencies字段 |
| 漏洞嵌入 | 需要外部关联 | 1.5版本开始原生支持 |
| 支持格式 | JSON、Tag-value、RDF/XML | JSON、XML、Protobuf |
| 工具链成熟度 | 非常成熟,尤其是合规审计工具 | 快速成熟,安全工具支持好 |
| 文件体积 | 较大(尤其是包含完整许可证文本时) | 较小 |
那么问题来了——到底该选哪个?
我个人习惯是这样判断的:
- 如果你的主要诉求是许可证合规审计(比如要过OpenChain认证),选SPDX。它对许可证的描述粒度是CycloneDX比不了的。
- 如果你的主要诉求是漏洞扫描和依赖管理(比如要做日常的CVE监控),选CycloneDX。它的PURL和原生漏洞支持会让你的工作流顺畅很多。
- 如果你两个都要——嗯,我建议你两个都生成。反正工具链支持双格式输出,存储成本也不高。我在一个大型金融项目中就是这么干的:SPDX给法务和合规部门,CycloneDX给安全运维团队。
最后说一句——格式只是载体,真正重要的是SBOM里的数据质量。不管选哪种格式,确保组件信息完整、版本号准确、校验值可验证,这才是硬道理。