3、SBOM格式解析:SPDX与CycloneDX深度拆解

说到SBOM的格式,市面上主流的就两个——SPDX和CycloneDX。我刚开始接触SBOM的时候,也被这两个格式搞得有点晕。后来在几个实际项目里反复折腾,才真正摸清了它们的脾气。今天我就把这两套格式掰开揉碎了讲给你听。

说白了,SPDX和CycloneDX就像两种不同的语言,都能描述软件供应链,但语法和侧重点不一样。你想想看,选错了格式,后面解析、对比、生成报告都会很痛苦。所以这一节,咱们把它们的细节都过一遍。

SBOM 主流格式全景图 SPDX JSON 格式 Tag-value 格式 RDF/XML 格式 CycloneDX JSON 格式 XML 格式 Protobuf 格式 核心差异 SPDX 由 Linux 基金会主导,侧重许可证合规与版权信息 CycloneDX 由 OWASP 主导,侧重安全漏洞与组件依赖关系

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,是后续做漏洞匹配的关键。
我的经验: 在生成SPDX JSON时,一定要把checksums字段填完整。我曾经遇到过一个项目,因为缺少SHA256校验值,导致后续的完整性验证全部失败,排查了半天才发现是生成工具配置漏了。

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体积更小)
避坑指南: 我曾经在对接一个客户的审计系统时,发现他们只支持SPDX 1.2的Tag-value格式。而我们的工具默认生成的是2.3。结果花了整整两天做格式转换和字段映射。所以,在项目开始前,一定要先确认下游系统支持的SPDX版本和格式。

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字段,可以直接表达组件之间的依赖关系。

关键点: CycloneDX 1.5版本开始,支持直接在SBOM中嵌入漏洞信息(vulnerabilities字段)。这意味着你可以把扫描结果和SBOM合并成一个文件,管理起来非常方便。

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是更好的选择。但缺点也很明显:文件体积大,解析速度慢。

我的建议: 在微服务架构中,我倾向于用JSON格式。因为每个服务生成的SBOM都要上传到中央仓库,JSON体积小,传输快。但在金融、政务等对数据完整性要求极高的场景,XML的Schema校验能力就很有价值。

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给安全运维团队。
避坑指南: 我曾经在一个项目中只生成了SPDX格式,结果安全团队做漏洞扫描时发现,SPDX的CPE字段很多组件都匹配不上。后来换成CycloneDX,用PURL匹配,准确率从70%提升到了95%以上。所以,如果你主要做漏洞扫描,CycloneDX是更省心的选择。

最后说一句——格式只是载体,真正重要的是SBOM里的数据质量。不管选哪种格式,确保组件信息完整、版本号准确、校验值可验证,这才是硬道理。