SBOM 标准与格式:SPDX、CycloneDX、SWID 详解
聊 SBOM,绕不开三个标准:SPDX、CycloneDX 和 SWID。我刚开始接触时也懵,心想「搞这么多种干嘛,统一一个不好吗?」后来踩过坑才明白——各有各的出身,各有各的擅长。
这一章,我把这三个格式掰开揉碎讲清楚。你以后选型时,心里就有底了。
SPDX 格式详解
SPDX(Software Package Data Exchange)是 Linux 基金会搞的。它诞生最早,2011 年就出了 1.0。说白了,它是个「老大哥」级别的标准。
核心思想:用一套统一字段,描述软件包的组成、许可证、版权信息。
SPDX 文档的核心结构长这样:
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: my-app-sbom
CreationInfo:
Creators: Tool: sbom-tool-1.0
Created: 2024-01-15T10:00:00Z
PackageName: my-app
SPDXID: SPDXRef-Package-my-app
PackageVersion: 1.0.0
PackageLicenseConcluded: MIT
Relationship: SPDXRef-Package-my-app DEPENDS_ON SPDXRef-Package-libfoo
嗯,这里要注意:SPDX 用 Relationship 字段表达依赖关系。它支持几十种关系类型,比如 DEPENDS_ON、BUILD_TOOL_OF、CONTAINED_BY。我个人习惯用 DEPENDS_ON 和 BUILD_DEPENDENCY_OF 就够了,太多反而乱。
LicenseInfoInFile 字段,可以精确到每个文件的许可证。我在审计一个开源项目时,发现 80% 文件是 MIT,但有个核心文件是 GPL——多亏 SPDX 的细粒度,才没漏掉这个合规风险。
SPDX 的优缺点:
- ✅ 许可证信息最详细,合规审计首选
- ✅ 社区成熟,工具链丰富
- ❌ 文件体积偏大,依赖关系表达不够直观
- ❌ 对容器镜像、微服务架构支持较弱
CycloneDX 格式详解
CycloneDX 是 OWASP 社区推的。它出生晚(2017 年),但发展快。为什么?因为它专为「应用安全」而生。
CycloneDX 用 JSON 或 XML 表达。我个人更爱 JSON,可读性好。来看一个例子:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"metadata": {
"timestamp": "2024-01-15T10:00:00Z",
"tools": [{"vendor": "my-org", "name": "sbom-tool"}]
},
"components": [
{
"type": "library",
"name": "libfoo",
"version": "2.1.0",
"purl": "pkg:npm/libfoo@2.1.0",
"licenses": [{"license": {"id": "MIT"}}]
}
],
"dependencies": [
{
"ref": "pkg:npm/my-app@1.0.0",
"dependsOn": ["pkg:npm/libfoo@2.1.0"]
}
]
}
你发现没?CycloneDX 用 purl(Package URL)标识组件。这是个好东西——全球统一,不会搞混。我在项目中遇到过,同一个组件在不同仓库里名字不一样,用 purl 就彻底解决了。
vulnerabilities 数组,直接指向 CVE 编号。做安全扫描时,一步到位。
CycloneDX 的优缺点:
- ✅ 依赖关系清晰,支持嵌套和循环
- ✅ 原生集成漏洞数据,安全团队最爱
- ✅ 支持容器、微服务、硬件等 20+ 组件类型
- ❌ 许可证信息不如 SPDX 详细
- ❌ 早期版本兼容性有点坑(我踩过 1.2 升 1.4 的雷)
SWID 标签介绍
SWID(Software Identification Tag)是 ISO 标准(ISO/IEC 19770-2)。它出身「企业软件管理」领域,跟 SPDX 和 CycloneDX 不是一个路子。
SWID 标签通常嵌入在安装包或二进制文件里。它长这样(XML 格式):
<SoftwareIdentity
tagId="com.example.my-app-1.0.0"
name="my-app"
version="1.0.0"
versionScheme="multipartnumeric">
<Entity name="Example Corp" role="softwareCreator"/>
<Link rel="license" href="https://example.com/license"/>
<Meta persist="true">checksum=sha256:abc123...</Meta>
</SoftwareIdentity>
SWID 的核心是 tagId——全局唯一。它不像 SPDX 那样用 SPDXID,也不像 CycloneDX 用 purl,而是自己一套体系。
SWID 的优缺点:
- ✅ ISO 标准,企业合规部门认它
- ✅ 适合软件资产管理(SAM)场景
- ❌ 依赖关系表达弱,基本只能描述「单个软件」
- ❌ 工具链少,社区活跃度低
- ❌ 生成方式受限,不适合 CI/CD 动态扫描
格式对比与选型
三个格式摆在这,怎么选?我画了张图,帮你理清思路:
下面这张表,把三个格式的核心差异列清楚:
| 对比维度 | SPDX | CycloneDX | SWID |
|---|---|---|---|
| 出身 | Linux 基金会 | OWASP | ISO/IEC |
| 诞生年份 | 2011 | 2017 | 2009 |
| 核心用途 | 许可证合规 | 安全漏洞管理 | 软件资产盘点 |
| 依赖表达 | Relationship 字段 | dependencies 数组 | 弱(基本无) |
| 组件标识 | SPDXID | purl | tagId |
| 许可证粒度 | 文件级 | 组件级 | 组件级 |
| 漏洞关联 | 外部扩展 | 原生支持 | 不支持 |
| 容器支持 | 一般 | 优秀 | 差 |
| 工具链丰富度 | 高 | 高 | 低 |
| 文件格式 | Tag/JSON/YAML | JSON/XML | XML |
你想想看,三个格式其实不冲突。它们可以共存。我现在的项目里,CI/CD 流水线同时输出 CycloneDX 和 SPDX 两份 SBOM。安全团队看 CycloneDX,法务团队看 SPDX,各取所需。