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 就够了,太多反而乱。

我的经验:SPDX 的许可证字段非常强大。它有个 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 就彻底解决了。

CycloneDX 的杀手锏:它原生支持漏洞关联。每个组件可以挂 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,而是自己一套体系。

避坑指南:我曾经在一个 Windows 桌面软件项目里用 SWID 做资产盘点。结果发现,SWID 标签必须由软件安装器主动写入系统,如果安装器没实现,标签就不存在。说白了,它依赖「上游配合」。不像 SPDX 和 CycloneDX,你可以事后扫描生成。

SWID 的优缺点:

  • ✅ ISO 标准,企业合规部门认它
  • ✅ 适合软件资产管理(SAM)场景
  • ❌ 依赖关系表达弱,基本只能描述「单个软件」
  • ❌ 工具链少,社区活跃度低
  • ❌ 生成方式受限,不适合 CI/CD 动态扫描

格式对比与选型

三个格式摆在这,怎么选?我画了张图,帮你理清思路:

SBOM 标准选型决策图 SPDX 许可证合规审计 CycloneDX 安全漏洞管理 SWID 企业资产盘点 场景:合规审计 场景:安全扫描 场景:资产盘点 选型建议 合规优先 → SPDX | 安全优先 → CycloneDX | 资产盘点 → SWID 通用场景:CycloneDX + SPDX 双格式输出,覆盖安全和合规

下面这张表,把三个格式的核心差异列清楚:

对比维度 SPDX CycloneDX SWID
出身 Linux 基金会 OWASP ISO/IEC
诞生年份 2011 2017 2009
核心用途 许可证合规 安全漏洞管理 软件资产盘点
依赖表达 Relationship 字段 dependencies 数组 弱(基本无)
组件标识 SPDXID purl tagId
许可证粒度 文件级 组件级 组件级
漏洞关联 外部扩展 原生支持 不支持
容器支持 一般 优秀 差
工具链丰富度 高 高 低
文件格式 Tag/JSON/YAML JSON/XML XML
我的选型建议:如果你刚开始做 SBOM,别纠结。先上 CycloneDX,因为它工具链最友好,安全团队也认。等合规审计需求来了,再加 SPDX。SWID 嘛——除非你客户明确要求 ISO 标准,否则暂时不用碰。

你想想看,三个格式其实不冲突。它们可以共存。我现在的项目里,CI/CD 流水线同时输出 CycloneDX 和 SPDX 两份 SBOM。安全团队看 CycloneDX,法务团队看 SPDX,各取所需。