1. SBOM 基础概念:从一份“软件成分清单”说起

大家好,我是你们的讲师。今天咱们开始聊 SBOM——软件物料清单。这词儿听起来挺唬人,说白了就是一份“你家软件里都用了啥”的清单。

我记得几年前帮一家金融客户做安全审计,对方 CTO 拍着桌子问:“我们这产品到底引了多少开源组件?”没人答得上来。那时候我就意识到,没有 SBOM,你连自己家底都摸不清,还谈什么安全?

1.1 什么是 SBOM?

SBOM,全称 Software Bill of Materials。你可以把它想象成食品包装袋上的配料表。

买一包薯片,配料表会告诉你:土豆、植物油、食用盐、添加剂…… 每一行都清清楚楚。SBOM 就是软件的配料表——它列出了构成一个软件产品的所有“食材”:组件名称、版本号、依赖关系、许可证信息。

核心定义:SBOM 是一份结构化、机器可读的清单,记录了软件供应链中所有组件的元数据。它不是文档,是数据。

为什么需要它?你想想看,如果 Log4j 爆出漏洞,你第一反应是什么?——“我项目里用没用 Log4j?哪个版本?” 没有 SBOM,你得翻 pom.xml、package.json、Dockerfile…… 一个个找。有 SBOM,一行命令就能查出来。

我的经验: 我习惯把 SBOM 生成集成到 CI/CD 流水线里,每次构建自动生成一份。这样一旦有漏洞预警,5 分钟内就能定位受影响的服务。

1.2 SBOM 的组成要素

一份完整的 SBOM,至少包含四个核心要素。咱们一个一个说。

1.2.1 组件(Component)

组件就是软件里的每一个“零件”。它可以是:

  • 一个开源库(比如 log4j-core)
  • 一个第三方 SDK(比如 AWS SDK)
  • 一个容器基础镜像(比如 alpine:3.18)
  • 甚至是你自己写的内部模块

每个组件都需要一个唯一的标识符。常用的有:

  • PURL(Package URL):比如 pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1
  • CPE(Common Platform Enumeration):比如 cpe:2.3:a:apache:log4j:2.17.1

避坑指南: 我曾经遇到一个项目,SBOM 里只写了组件名,没写 PURL。结果漏洞扫描工具根本匹配不到 CVE。记住:标识符必须用标准格式,否则 SBOM 就是废纸。

1.2.2 版本(Version)

版本号是 SBOM 的灵魂。同一个组件,不同版本可能天差地别。log4j 2.14.1 有 RCE 漏洞,2.17.1 就修复了。没有版本号,你根本不知道风险有多大。

版本号通常遵循语义化版本规范(SemVer):主版本.次版本.补丁。但要注意,有些项目会用时间戳或 Git commit hash 做版本,SBOM 里也要如实记录。

1.2.3 依赖关系(Dependency)

组件不是孤立的。A 依赖 B,B 依赖 C,C 又依赖 D…… 这就是依赖树。SBOM 必须把这种关系说清楚。

举个例子:

my-app:1.0.0
├── spring-boot-starter-web:3.1.0
│   ├── spring-core:6.0.9
│   │   └── spring-jcl:6.0.9
│   └── tomcat-embed-core:10.1.12
└── log4j-core:2.17.1
    └── log4j-api:2.17.1

为什么要记录依赖关系?因为漏洞会“传染”。如果 spring-core 有漏洞,所有间接依赖它的组件都受影响。没有依赖关系图,你根本算不清影响范围。

1.2.4 许可证(License)

许可证是法务部门最关心的。GPL、MIT、Apache 2.0、BSD…… 不同许可证对商用、分发、修改有不同要求。

我见过一个创业公司,用了 GPL 协议的库,结果产品被要求开源全部代码——差点倒闭。SBOM 里记录许可证,就是为了避免这种“许可证中毒”。

许可证 商用允许 修改后必须开源 典型组件
MIT ✅ ❌ React, jQuery
Apache 2.0 ✅ ❌ Spring, Kubernetes
GPL v3 ✅ ✅ Linux 内核部分模块
BSD 3-Clause ✅ ❌ Nginx, Redis

1.3 SBOM 的格式标准

光有内容还不够,格式得统一。不然你拿 JSON,我用 XML,他写 YAML,根本没法互通。目前业界主流就两个标准:SPDX 和 CycloneDX。

1.3.1 SPDX

SPDX(Software Package Data Exchange)由 Linux 基金会维护。它诞生最早,2011 年就出了 1.0 版本。特点是:

  • 许可证信息极其详细——SPDX 维护了一个庞大的许可证列表,每个许可证都有唯一 ID
  • 文档结构严谨——适合合规审计场景
  • 支持多种格式:RDF/XML、XLSX、JSON、YAML、Tag:Value

SPDX 2.3 是目前最广泛使用的版本。如果你做的是合规性要求高的项目(比如汽车、医疗),SPDX 是首选。

1.3.2 CycloneDX

CycloneDX 由 OWASP 维护。它更年轻(2017 年才出 1.0),但发展很快。特点是:

  • 专为安全场景设计——原生支持漏洞引用、组件风险评分
  • 轻量级——JSON 格式,解析快,适合 CI/CD 流水线
  • 支持更多组件类型:容器、固件、SaaS、机器学习模型……

我个人习惯用 CycloneDX。为什么?因为它跟漏洞扫描工具配合得最好。OWASP Dependency-Check、Trivy、Grype 都原生支持 CycloneDX 格式。

特性 SPDX CycloneDX
维护组织 Linux 基金会 OWASP
首次发布 2011 2017
核心优势 许可证管理、合规审计 漏洞管理、安全集成
组件类型 软件包、文件 软件、容器、固件、SaaS
漏洞支持 基础(外部引用) 原生(漏洞对象、评分)
推荐场景 法务合规、供应链披露 DevSecOps、漏洞扫描

1.3.3 一个简单的 CycloneDX 示例

光说不练假把式。咱们看一段真实的 CycloneDX JSON:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "version": 1,
  "metadata": {
    "timestamp": "2024-03-15T10:00:00Z",
    "tools": [
      {
        "vendor": "OWASP",
        "name": "CycloneDX Maven Plugin",
        "version": "2.7.0"
      }
    ],
    "component": {
      "type": "application",
      "name": "my-app",
      "version": "1.0.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"
          }
        }
      ]
    }
  ],
  "dependencies": [
    {
      "ref": "pkg:maven/com.example/my-app@1.0.0",
      "dependsOn": [
        "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.1"
      ]
    }
  ]
}

看到没?组件、版本、PURL、许可证、依赖关系,全在里面。机器读起来毫不费力。

1.4 SBOM 知识体系总览

为了让你对本章内容有个整体印象,我画了张图:

SBOM 知识体系总览 SBOM 组成要素 组件 版本 依赖关系 许可证 格式标准 SPDX CycloneDX 核心价值:可见性 → 可管理 → 可修复 标识符:PURL / CPE 漏洞引用 / 风险评分

这张图把 SBOM 的核心脉络串起来了。左边是“有什么”,右边是“怎么写”,底部是“为什么做”。

我的建议: 刚开始接触 SBOM,别纠结选 SPDX 还是 CycloneDX。先跑起来,生成一份看看长什么样。我当年就是从 mvn org.cyclonedx:cyclonedx-maven-plugin:makeBom 这条命令开始的。