SBOM 核心概念与数据模型:三大标准格式详解

聊 SBOM,绕不开三个标准:SPDX、CycloneDX、SWID。很多人一上来就问「哪个最好?」——我个人的习惯是,先别急着选,搞清楚它们各自长什么样、能干什么,再说。

说白了,SBOM 就是一份「软件成分清单」。但这份清单怎么写、写多细,不同标准有不同玩法。咱们一个一个看。

SPDX:最老牌、最通用

SPDX(Software Package Data Exchange)由 Linux 基金会维护,诞生最早,社区最成熟。我最早接触 SBOM 就是用的 SPDX 2.2,那时候 CycloneDX 还没这么火。

SPDX 的核心思路是:一个文件描述一个软件包。它把信息分成几个大块:

  • 文档信息:谁创建的、什么时候、用什么工具
  • 包信息:包名、版本、下载地址、校验和
  • 文件信息:每个文件的版权、许可证
  • 许可证信息:声明的许可证、实际检测到的许可证
  • 关系信息:包与包之间的依赖关系

举个例子,一个简单的 SPDX 片段长这样:

SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: my-iot-firmware-v1.0
Creator: Tool: sbom-tool-0.1
Created: 2024-01-15T10:00:00Z

##### Package: openssl
PackageName: openssl
SPDXID: SPDXRef-openssl
PackageVersion: 1.1.1t
PackageDownloadLocation: https://github.com/openssl/openssl/archive/refs/tags/OpenSSL_1_1_1t.tar.gz
PackageChecksum: SHA256: c9913c7a8b8c8c8b8c8b8c8b8c8b8c8b8c8b8c8b8c8b8c8b8c8b8c8b8c8b8c8b
PackageLicenseConcluded: OpenSSL
PackageLicenseDeclared: OpenSSL and SSLeay

嗯,这里要注意:SPDX 的字段名是大小写敏感的,写错了解析器会报错。我曾经在项目里因为把 PackageLicenseConcluded 写成了 PackageLicenseConcluded(少了个字母),结果 CI 流水线卡了一整天。

CycloneDX:轻量、面向现代应用

CycloneDX 由 OWASP 社区推动,一开始就瞄准了「现代软件供应链安全」。它的数据模型更紧凑,用 JSON 或 XML 表达,对容器镜像、微服务、云原生场景支持更好。

我个人觉得 CycloneDX 最大的优势是:字段设计更贴近实际安全分析需求。比如它原生支持「组件类型」——是库、框架、操作系统、还是容器?这在物联网场景下特别有用,因为你的设备里可能同时有 Linux 内核、OpenSSL 库、一个 Java 应用、还有几个 Python 脚本。

一个 CycloneDX 的 JSON 示例:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
  "version": 1,
  "metadata": {
    "timestamp": "2024-01-15T10:00:00Z",
    "tools": [{"vendor": "my-org", "name": "sbom-gen", "version": "1.0"}]
  },
  "components": [
    {
      "type": "library",
      "name": "openssl",
      "version": "1.1.1t",
      "purl": "pkg:generic/openssl@1.1.1t",
      "licenses": [{"license": {"id": "OpenSSL"}}],
      "hashes": [{"alg": "SHA-256", "content": "c9913c7a..."}]
    }
  ]
}

看到那个 purl 了吗?这是 CycloneDX 的亮点——用 Package URL 统一标识组件,不管它来自 npm、PyPI、Maven 还是 GitHub。你想想看,如果没有这个,你拿什么去匹配漏洞数据库?

SWID:微软和 ISO 的「官方」方案

SWID(Software Identification)标签是 ISO/IEC 19770-2 标准,微软在 Windows 生态里推得比较多。它的格式基于 XML,结构上更像「软件身份证」——每个软件安装后生成一个标签文件,记录软件身份、版本、发布者。

SWID 在物联网里用得相对少,但有一个场景我遇到过:设备固件出厂预装软件的场景。比如你的网关设备里预装了某个 RTOS 和几个中间件,用 SWID 标签可以做到「一机一证」,方便后续审计。

一个简化的 SWID 标签:

<SoftwareIdentity
  xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd"
  name="OpenSSL"
  version="1.1.1t"
  tagId="openssl-1.1.1t-x86-64"
  versionScheme="multipartnumeric">
  <Entity name="OpenSSL Foundation" role="tagCreator"/>
  <Meta persist="true" />
</SoftwareIdentity>

不过说实话,SWID 的 XML 结构比较啰嗦,解析起来比 JSON 费劲。我在实际项目中很少单独用 SWID,更多是把它作为 SPDX 或 CycloneDX 的补充——比如 Windows 设备上的软件清单,用 SWID 采集,再转成 CycloneDX 统一管理。

三大标准对比

维度 SPDX CycloneDX SWID
维护组织 Linux 基金会 OWASP ISO / 微软
数据格式 Tag-value / JSON / RDF JSON / XML XML
核心粒度 包 + 文件 组件 软件实例
许可证追踪 ★★★★★ ★★★★ ★★
依赖关系 ★★★★ ★★★★★ ★★★
物联网适用性 ★★★★ ★★★★★ ★★★

SBOM 的必填字段与可选字段

不管用哪个标准,一份合格的 SBOM 至少要有这些信息。我把它们分成「生存线」和「加分项」:

必填字段(少了就不叫 SBOM)

  • 组件名称:比如 openssl、libcurl
  • 组件版本:1.1.1t、7.79.1
  • 组件唯一标识:SPDXID、purl、或 SWID tagId
  • 依赖关系:谁依赖谁
  • 文档创建时间:什么时候生成的
  • 创建者信息:谁生成的(工具或人)

可选字段(但强烈建议加上)

  • 许可证信息:不填的话,法务部门会找你喝茶
  • 校验和:SHA256,用于验证组件完整性
  • 下载地址:方便自动化工具拉取源码
  • 组件类型:库、框架、操作系统、容器
  • 供应商/作者:出了漏洞找谁问
  • 外部引用:CVE 编号、安全公告链接

我的经验之谈:在物联网项目里,组件类型和校验和这两个可选字段,我建议你当成必填来对待。为什么?因为物联网设备里组件来源复杂——有的是从芯片厂商拿的 BSP,有的是从开源社区拉的,还有的是自己写的。没有类型和校验和,你根本没法做自动化漏洞匹配。

最小可行 SBOM 的定义

「最小可行 SBOM」这个概念,说白了就是:在保证安全分析能力的前提下,SBOM 最少要包含哪些字段?

我参与过几个物联网安全标准制定,大家基本达成共识:最小可行 SBOM 至少包含以下 5 个字段:

  1. 组件名称 —— 知道是什么
  2. 组件版本 —— 知道是哪个版本
  3. 唯一标识符 —— 能跨系统引用
  4. 依赖关系 —— 知道组件之间的连接
  5. 创建时间 —— 知道这份清单的新鲜度

你可能会问:许可证呢?校验和呢?嗯,这些确实重要,但「最小可行」的意思是——没有这 5 个字段,SBOM 基本没法用。有了这 5 个,至少你能回答「我的设备里装了哪些软件、什么版本、谁依赖谁」这三个核心问题。

避坑指南:我曾经在一个网关项目里,客户要求提供 SBOM,但只给了组件名和版本号,没有依赖关系。结果漏洞扫描工具跑完,报了一堆「依赖冲突」——因为同一个库被不同组件引用了不同版本,但 SBOM 里根本看不出来。从那以后,我坚持「依赖关系」必须进最小集。

三大标准与最小可行 SBOM 的关系

用一张图来总结本章的核心逻辑:

SBOM 三大标准与最小可行模型 SPDX CycloneDX SWID 共同核心:最小可行 SBOM 组件名称 · 版本 · 唯一标识 · 依赖关系 · 创建时间 许可证合规审计 漏洞扫描与匹配 供应链溯源 无论选择哪种标准,最小可行 SBOM 是安全分析的底线 物联网场景建议优先选用 CycloneDX,兼顾轻量与安全需求

从这张图可以看得很清楚:SPDX、CycloneDX、SWID 各有侧重,但最终都收敛到「最小可行 SBOM」这个共同核心上。你在实际项目中,可以根据设备类型、合规要求、工具链成熟度来选择标准——但不管选哪个,先把那 5 个必填字段填好,再谈其他的。

注意:不要为了「最小」而「最小」。最小可行 SBOM 是起点,不是终点。我见过有些团队为了省事,只填了组件名和版本号,结果漏洞扫描工具跑出来一堆误报——因为没有依赖关系,工具没法判断组件是否真的被使用。记住:最小可行 ≠ 最小可用。