软件物料清单(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不是终点,而是起点。它从源码、包管理、容器镜像等输入源生成,然后输出给漏洞扫描、许可证审计、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,但真正的价值在于你怎么用它来驱动安全决策。