SBOM 的组成要素:拆开来看,其实就五样东西

说实话,我刚接触 SBOM 那会儿,觉得这东西挺玄乎的。什么 CycloneDX、SPDX 标准,一堆 XML 和 JSON,看着就头大。但后来我亲手搭过几次供应链安全体系之后,才明白——SBOM 说白了就是一张软件的「成分清单」,跟食品包装袋背后的配料表一个道理。

那这张清单里到底要写什么?我习惯把它拆成五个核心要素。你把这五个要素搞清楚了,SBOM 就算入门了。

1. 组件名称:你用的是哪个「东西」?

组件名称,就是软件里引用的那个库、框架或者工具的名字。比如 log4j、spring-boot、openssl。听起来简单吧?但坑就在这里。

我曾经踩过一个坑:同一个组件,不同生态叫法完全不同。比如 Java 里的 commons-logging,在 Maven 中央仓库叫 commons-logging:commons-logging,但在 npm 里压根没有。如果你只写个「logging」,下游根本不知道你用的是哪个。

所以,我建议组件名称一定要带上命名空间(namespace)或者分组(group)信息。比如:

  • Maven:org.apache.logging.log4j:log4j-core
  • npm:@angular/core
  • PyPI:django==4.2

嗯,这样才不会有歧义。

2. 版本号:精确到补丁级别

版本号是 SBOM 里最容易出问题的地方。很多人写个 1.0 就完事了,但 1.0 和 1.0.1 可能差了一个严重漏洞的修复。

我个人习惯是:版本号必须精确到 patch 版本,也就是三位数:主版本.次版本.补丁版本。比如 4.17.2,而不是 4.17。

一个小技巧:如果你用语义化版本(SemVer),那版本范围(比如 ^4.17.0)在 SBOM 里是不允许的。SBOM 要的是「锁定版本」,不是「版本范围」。你想想看,如果只知道一个范围,漏洞扫描器怎么知道你到底有没有中招?

3. 依赖关系:谁依赖谁?

这是 SBOM 里最复杂的一块。一个组件可能依赖十个子组件,每个子组件又依赖更多。我见过最夸张的一个项目,光依赖树就打印了 2000 多行。

依赖关系通常有两种表达方式:

类型 说明 示例
直接依赖 你在代码里显式引用的组件 spring-boot-starter-web
传递依赖 被直接依赖所依赖的组件 spring-boot-starter-web 依赖 tomcat-embed-core

为什么要区分这个?因为漏洞修复的优先级不一样。直接依赖你还能控制,传递依赖有时候连升级都费劲。我在项目里遇到过,一个传递依赖的漏洞,因为上游库不更新,我们被迫自己打补丁——那叫一个折腾。

4. 许可证信息:合规的「红线」

很多人觉得许可证是法务的事,跟技术没关系。但说实话,许可证问题能直接让产品下架。我见过一个创业公司,因为用了 GPL 协议的库,结果整个产品被迫开源,投资人差点撤资。

SBOM 里需要记录的许可证信息包括:

  • 许可证名称:比如 MIT、Apache 2.0、GPL 3.0
  • 许可证文本或链接:方便法务核对
  • 许可证兼容性:多个组件的许可证是否冲突
重点:许可证信息不是「有就行」,而是要「准确」。同一个组件在不同版本可能换了许可证,比如 MongoDB 从 3.6 之后从 AGPL 改成了 SSPL。如果你不更新 SBOM,合规审计一查一个准。

5. 哈希值:给组件上个「指纹」

哈希值,说白了就是给组件内容算一个唯一的「指纹」。常用的算法有 SHA-256、SHA-1(不推荐了)。

为什么需要哈希?因为名字和版本号都可以伪造。你下载了一个叫 log4j-2.14.1.jar 的文件,但谁能保证它真的是 Apache 官方发布的?哈希值就是用来做这个验证的。

我建议的做法是:

# 生成组件的 SHA-256 哈希
sha256sum log4j-core-2.17.2.jar
# 输出:a1b2c3d4...(64位十六进制字符串)

# 在 SBOM 中记录
"hashes": [
  {
    "alg": "SHA-256",
    "value": "a1b2c3d4e5f6..."
  }
]
注意:哈希值一定要在「可信环境」下生成。如果你从恶意镜像站下载了被篡改的组件,再算哈希,那这个哈希就是「毒指纹」。我一般会在 CI/CD 流水线里,从官方源下载后立即计算哈希,然后跟 SBOM 里的比对。

一张图看懂 SBOM 五要素

下面这张图,是我自己画的一个 SBOM 核心结构。你看一眼,基本就记住这五个要素了。

SBOM 组成要素结构图 SBOM 物料清单 ① 组件名称 ② 版本号 ③ 依赖关系 ④ 许可证信息 ⑤ 哈希值 五个要素缺一不可 缺少组件名称 → 不知道用了什么 缺少哈希值 → 无法验证组件完整性 缺少许可证 → 合规审计直接亮红灯

五要素之间的关系

这五个要素不是孤立的。我举个例子你就明白了:

假设你的项目里引用了 log4j-core,版本是 2.17.2,它的哈希值是 sha256:a1b2c3...,许可证是 Apache 2.0。同时,它依赖了 log4j-api 的 2.17.2 版本。这五条信息合在一起,才构成一个完整的 SBOM 条目。

核心观点:SBOM 的价值不在于「有」,而在于「准」。组件名称写错一个字,版本号少写一位,哈希值算错一个字符——整个 SBOM 就废了。我见过太多团队,SBOM 生成工具一跑就完事,结果漏洞爆发时才发现,SBOM 里的版本号跟实际部署的根本对不上。

嗯,这一章的内容就到这儿。五要素记住了吗?组件名称、版本号、依赖关系、许可证信息、哈希值——下次你看到一份 SBOM,按这五个维度去检查,基本不会漏东西。