软件物料清单(SBOM):SPDX与CycloneDX格式、生成工具、审计策略

各位做嵌入式安全的同行,咱们今天聊一个绕不开的话题——SBOM。说白了,就是给你的软件产品列一份详细的「配料表」。你想想看,做硬件的时候,BOM(物料清单)是标配,哪个电阻、哪个电容,清清楚楚。那软件呢?用了什么开源库、什么版本、有没有已知漏洞,这些信息如果一团浆糊,供应链安全就是一句空话。

我最早接触SBOM,是在一次车规级项目的安全审计中。客户要求我们提供完整的第三方组件清单,当时我们团队花了整整两周手工整理,还漏了好几个间接依赖。从那以后,我就养成了一个习惯:项目启动第一天,就把SBOM生成工具配好。

两种主流格式:SPDX vs CycloneDX

目前业界最主流的SBOM格式就两个:SPDX和CycloneDX。很多人问我选哪个,我的回答是——看场景。

对比维度 SPDX CycloneDX
维护组织 Linux基金会(SPDX工作组) OWASP(开源Web应用安全项目)
核心定位 许可证合规 + 版权信息 安全漏洞 + 组件依赖关系
文件格式 Tag:Value, RDF/XML, JSON, YAML XML, JSON, Protobuf
漏洞描述 通过外部引用关联CVE 内置vulnerability对象,原生支持
依赖图 支持,但粒度较粗 支持完整的依赖树和传递依赖
典型使用场景 法律合规审计、开源许可证管理 安全运维、漏洞扫描、CI/CD集成

我个人习惯是:许可证合规用SPDX,安全审计用CycloneDX。但如果你问我实际项目里怎么选,我建议两个都生成。工具链支持双格式输出,没必要二选一。

核心观点:SBOM不是一份静态文档,它是供应链安全的「数据底座」。没有SBOM,漏洞扫描、许可证审计、OTA差分更新,全都无从谈起。

生成工具:从手动到自动化

早期做SBOM,全靠人工翻代码、查文档。现在工具链已经很成熟了。我按语言和场景整理了一份清单,供你参考。

1. 通用工具

  • Syft(Anchore出品):支持容器镜像、文件系统、SBOM导出。我常用它做CI流水线里的SBOM生成步骤。
  • Trivy(Aqua Security):不仅能扫漏洞,也能生成SBOM。轻量、快,适合嵌入式环境。
  • SPDX Tools:官方工具集,支持多种格式互转。适合需要深度定制输出的场景。

2. 语言/平台专用工具

语言/平台 推荐工具 输出格式
C/C++ cve-bin-tool + 手动补充 SPDX, CycloneDX
Java/Maven Maven SBOM Plugin CycloneDX
Python pip-audit, cyclonedx-python CycloneDX
Node.js @cyclonedx/cyclonedx-npm CycloneDX
Yocto/Embedded Linux meta-spdxscanner SPDX

嗯,这里要注意:嵌入式环境往往没有包管理器。比如你用C语言裸写固件,或者用RTOS,依赖关系全靠手动维护。我曾经在一个Zephyr项目里,不得不写了个Python脚本,从CMakeLists.txt里解析第三方库路径,再调用Syft生成SBOM。虽然麻烦,但这一步省不了。

实战技巧:在CI/CD流水线里,把SBOM生成放在「构建完成」之后、「安全扫描」之前。这样既能保证SBOM反映的是最终产物,又能让漏洞扫描直接基于SBOM进行,避免重复解析。

审计策略:从生成到验证

SBOM生成只是第一步。真正的挑战在于——你怎么确保这份SBOM是完整、准确、可用的?我总结了一套「四步审计法」。

第一步:完整性检查

拿到SBOM后,先问三个问题:

  • 所有直接依赖都列全了吗?
  • 传递依赖(间接依赖)有没有遗漏?
  • 每个组件是否包含版本号、许可证、下载来源?

我曾经审计过一份SBOM,里面只列了20个直接依赖,但通过依赖分析工具一查,实际传递依赖有87个。这种「漏报」在安全审计里是致命的。

第二步:版本一致性校验

SBOM里写的版本号,和实际二进制里用的版本号,必须一致。怎么验证?

  • 对关键库文件计算哈希值(SHA256),与SBOM中记录的哈希比对。
  • 使用工具(如diffoscope)对比SBOM声明的源码版本和实际编译产物。

第三步:漏洞关联分析

把SBOM导入漏洞数据库(如NVD、GitHub Advisory Database),交叉匹配CVE。这里有个坑:不是所有漏洞都影响你的产品。比如某个漏洞只在特定配置下触发,而你的产品没用到那个功能。我建议做「可达性分析」——只关注那些真正能被攻击者利用的漏洞。

第四步:许可证合规审计

SPDX格式的优势在这里体现。检查每个组件的许可证类型,确认是否与你的产品许可证兼容。比如GPL v3的代码不能静态链接到商业闭源产品里。这个步骤建议让法务团队参与,但技术侧要提供准确的许可证信息。

警告:不要完全信任自动生成的SBOM。工具可能会漏掉一些「非标准」的依赖,比如通过git submodule引入的代码、手动下载的静态库、或者编译时从网络拉取的二进制。这些「灰色依赖」需要人工补充。

知识体系:SBOM在供应链安全中的位置

下面这张图,是我自己梳理的SBOM知识体系。它不是一个孤立的概念,而是连接「开发」和「运维」的桥梁。

SBOM 知识体系与供应链安全位置 SBOM 核心 源代码仓库 包管理器锁文件 容器镜像层 编译产物分析 漏洞扫描(CVE) 许可证合规审计 OTA差分计算 供应链透明度报告 Syft Trivy SPDX Tools CycloneDX CLI 工具链应集成到CI/CD流水线中,实现SBOM自动生成与审计

从这张图你能看到,SBOM不是终点,而是起点。它从源码、包管理、容器镜像等输入源生成,然后输出给漏洞扫描、许可证审计、OTA差分等下游系统。工具链(Syft、Trivy等)负责把输入转化为标准格式的SBOM。

一个实际的SBOM片段

最后,给你看一个真实的CycloneDX格式SBOM片段(JSON格式)。这是我之前在一个IoT网关项目里生成的,里面包含了一个开源MQTT库的依赖信息。

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.4",
  "version": 1,
  "components": [
    {
      "type": "library",
      "name": "paho-mqtt-c",
      "version": "1.3.12",
      "purl": "pkg:github/eclipse/paho.mqtt.c@1.3.12",
      "licenses": [
        {
          "license": {
            "id": "EPL-2.0"
          }
        }
      ],
      "hashes": [
        {
          "alg": "SHA-256",
          "content": "a1b2c3d4e5f6..."
        }
      ],
      "externalReferences": [
        {
          "type": "vcs",
          "url": "https://github.com/eclipse/paho.mqtt.c"
        }
      ]
    }
  ],
  "dependencies": [
    {
      "ref": "pkg:github/eclipse/paho.mqtt.c@1.3.12",
      "dependsOn": [
        "pkg:generic/openssl@1.1.1w"
      ]
    }
  ]
}

注意看dependencies字段,它明确标出了paho-mqtt-c依赖OpenSSL 1.1.1w。这个信息在安全审计时非常关键——如果OpenSSL 1.1.1w有已知漏洞,你就能立刻定位到受影响的组件。

小建议:在SBOM里尽量使用PURL(Package URL)格式标识组件。PURL是标准化的组件定位方式,能被大多数漏洞扫描工具直接识别。比你自己写个「libxxx v2.3」要靠谱得多。

好了,关于SBOM的格式、工具和审计策略,今天就聊到这儿。记住一句话:没有SBOM的供应链安全,就像没有地图的航行。工具可以帮你生成SBOM,但真正的价值在于你怎么用它来驱动安全决策。