4. 组件清单与SBOM
在固件供应链治理中,组件清单是治理对象的最小集合,而SBOM(Software Bill of Materials,软件物料清单)则是把这份清单标准化、可交换、可追溯的载体。没有SBOM,固件里的第三方库、开源组件、静态链接代码、二进制驱动就只能靠人工猜测;有了SBOM,才能把“这个固件里到底有什么”变成可查询、可比对、可审计的数据。
本节围绕三个问题展开:固件SBOM用什么标准表达、怎么从固件里生成、生成到什么粒度才够用,以及为什么在固件场景下这件事比在普通应用软件里难得多。
一、两种主流标准:SPDX与CycloneDX
当前固件SBOM最常用的两种标准是SPDX和CycloneDX。它们都描述组件、版本、许可证、依赖关系和唯一标识,但设计取向不同。
SPDX由Linux基金会维护,ISO/IEC 5962是其国际标准版本。它的核心是“文档—包—文件”三层结构:一个SPDX文档包含若干Package,每个Package可展开到File级别,并记录文件校验和、许可证结论、版权信息。SPDX对许可证表达非常严谨,适合需要法律合规审查的场景。它的标识符体系以SPDXID为主,外部引用通过ExternalRef关联CPE、PURL等。
CycloneDX由OWASP社区推动,最初面向应用安全,后来扩展到固件和硬件。它以“组件(component)”为中心,天然支持嵌套依赖、服务、漏洞引用和VEX(漏洞可利用性交换)。CycloneDX的JSON结构更紧凑,工具链集成友好,适合在CI/CD中自动生成和消费。它用bom-ref作为组件引用键,用purl作为组件坐标,能直接挂接漏洞库。
选择建议:如果固件需要对外交付合规证明、许可证审计要求高,优先SPDX;如果固件在持续集成中频繁生成、需要和漏洞扫描联动,优先CycloneDX。两者并非互斥,很多团队同时输出,用SPDX做合规归档,用CycloneDX做安全运营。
二、生成方法:从源码、构建到二进制
固件SBOM的生成通常有三条路径,实际项目中往往组合使用。
源码级扫描是最直接的方式。工具读取依赖清单文件,例如C/C++项目的conanfile.txt、vcpkg.json,Rust项目的Cargo.lock,以及Yocto/Buildroot的配方文件,解析出组件名、版本、许可证和依赖关系。这种方式准确率高,但只能覆盖“声明了依赖”的部分,对直接拷贝进源码树的第三方代码无能为力。
构建过程插桩是在编译和链接阶段采集信息。例如在CMake中通过--graphviz导出目标依赖图,在链接器包装脚本中记录每个.o来自哪个库,或者使用编译器插件记录头文件包含路径。这种方式能捕捉到实际参与构建的组件,但需要改造构建系统,且对预编译二进制无效。
二进制成分分析是固件场景的兜底手段。工具从固件镜像中提取可打印字符串、符号表、版本号、许可证声明片段,再与已知组件指纹库比对。例如在镜像中发现OpenSSL 1.1.1k字符串,或识别出zlib的特定常量表,就可以推断组件存在。这种方式覆盖最全,但存在误报和漏报,且无法还原完整依赖关系。
一个可操作的组合流程是:源码扫描产出基础SBOM,构建插桩补充实际链接关系,二进制分析做差异比对和兜底,最后合并去重、统一标识、签名输出。合并时要注意同一组件在不同来源中可能名称不同,需要用PURL或CPE做归一化。
三、粒度控制:组件级、文件级与片段级
SBOM粒度决定了治理的精度和成本。固件场景常见三种粒度:
- 组件级:只记录库或包的名称、版本、许可证。适合快速盘点、许可证合规初筛。缺点是同一个库的不同文件可能许可证不同,组件级会掩盖这种差异。
- 文件级:记录每个可执行文件、配置文件、资源文件的归属和哈希。适合需要精确定位漏洞影响范围的场景,例如某个CVE只影响库中的特定文件。
- 片段级:记录到函数或代码片段级别。适合高安全等级固件,但生成和维护成本极高,通常只在关键模块使用。
粒度选择的原则是“够用即可”。如果治理目标是回答“这个固件里有没有Log4j”,组件级足够;如果要回答“这个CVE是否影响我的固件”,文件级更可靠;如果要做二进制级溯源和补丁验证,才需要片段级。过粗会漏报,过细会导致SBOM体积膨胀、更新困难、工具链不堪重负。
四、固件场景的落地难点
固件SBOM之所以比应用软件SBOM难,根源在于固件的构建和交付方式。
静态链接与代码融合是首要难点。应用软件依赖动态库,运行时可以枚举;固件通常把库静态链接进单一镜像,库代码和业务代码在二进制层面已经融合,没有独立的组件边界。SBOM工具只能靠符号和字符串推断,精度受限。
交叉编译与工具链差异带来第二层困难。固件在x86主机上编译,目标却是ARM、RISC-V或MIPS。构建系统、编译器版本、C库实现(glibc/musl/newlib)都会影响组件识别。同一个库在不同工具链下可能表现出不同的符号和字符串特征,指纹库需要覆盖多种组合。
二进制裁剪与压缩进一步削弱可分析性。为了控制固件体积,链接器会丢弃未使用的函数,strip会移除符号表,压缩会打乱字符串。这些操作让二进制分析工具失去关键线索,只能依赖残留的版本字符串或常量特征。
多镜像与多分区使SBOM边界复杂化。一个固件产品可能包含Bootloader、RTOS、应用固件、文件系统镜像、FPGA比特流等多个部分,每部分由不同团队或供应商提供。SBOM需要明确覆盖范围,否则会出现“清单里有但镜像里没有”或“镜像里有但清单里没有”的偏差。
供应商不提供组件信息是最现实的障碍。很多第三方驱动、预编译库、芯片厂商SDK不公开依赖清单,也不提供SBOM。治理团队只能通过逆向分析、合同约束、采购要求逐步推动。在无法获取信息时,应在SBOM中明确标注“未知组件”和推断依据,而不是留空或伪造。
总结来说,固件SBOM不是一次性的文档,而是贯穿采购、开发、构建、发布、运维的持续数据流。标准选择决定交换能力,生成方法决定覆盖率,粒度控制决定治理精度,而对固件特殊性的清醒认识决定这套体系能否真正落地。