3. 硬件物料清单(HBOM)与软件物料清单(SBOM)工程

在IoT设备供应链安全中,HBOM与SBOM是两条并行的“成分账本”。HBOM记录设备中所有物理物料——主控芯片、无线模组、传感器、Flash、电源管理IC、连接器,甚至外壳与PCB的层压材料;SBOM记录固件与操作系统中所有软件组件——内核、驱动、协议栈、第三方库、配置文件与构建脚本。两者共同回答一个核心问题:这台设备到底由什么构成,每个成分来自哪里,存在哪些已知漏洞。

HBOM与SBOM并非简单的清单罗列,而是需要与供应链、漏洞库、构建系统形成可追溯的关联。对于IoT设备,硬件与软件高度耦合:一颗Wi-Fi模组的固件版本可能决定其协议栈是否受某个CVE影响;一颗MCU的ROM bootloader可能无法升级,从而形成永久性风险。因此,HBOM与SBOM必须能够通过“设备型号—批次—固件版本—组件版本”这条链路进行联合查询。

数据格式:SPDX与CycloneDX的工程选择

当前主流的SBOM格式是SPDX与CycloneDX。SPDX由Linux基金会维护,强调许可证合规与文件级溯源,适合需要严格许可证审计的场景;CycloneDX由OWASP社区推动,原生支持漏洞(VEX)、服务与硬件描述,更适合安全漏洞追溯与IoT设备。两者都支持JSON、XML等序列化方式,但字段模型不同。

以CycloneDX 1.5为例,一个最小SBOM片段如下:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "metadata": {
    "component": {
      "type": "firmware",
      "name": "iot-gateway-fw",
      "version": "2.3.1"
    }
  },
  "components": [
    {
      "type": "library",
      "name": "mosquitto",
      "version": "2.0.11",
      "purl": "pkg:github/eclipse/mosquitto@2.0.11",
      "bom-ref": "pkg:github/eclipse/mosquitto@2.0.11"
    },
    {
      "type": "library",
      "name": "openssl",
      "version": "1.1.1k",
      "purl": "pkg:generic/openssl@1.1.1k",
      "bom-ref": "pkg:generic/openssl@1.1.1k"
    }
  ]
}

其中purl(Package URL)是跨格式的组件唯一标识,bom-ref用于在依赖关系与漏洞声明中引用该组件。SPDX则使用SPDXID与PackageName、PackageVersion、ExternalRef等字段表达类似信息。工程上建议:若下游漏洞平台支持CycloneDX,优先使用CycloneDX;若需要与许可证扫描工具链深度集成,可同时输出SPDX。

生成工具:Syft与Tern的定位差异

Syft是Anchore开源的SBOM生成器,擅长从容器镜像、文件系统、目录中提取软件包信息,支持APK、DEB、RPM、Go模块、Python包、npm包等多种生态,输出SPDX与CycloneDX。Tern则更聚焦于容器镜像与固件镜像的分层分析,能够识别Dockerfile层、文件系统层,并生成更细粒度的组件清单。对于IoT固件,常见做法是先用binwalk解包固件,再用Syft扫描解包后的根文件系统。

一个典型的固件SBOM生成流程如下:

# 1. 解包固件
binwalk -e firmware.bin

# 2. 定位根文件系统
ls _firmware.bin.extracted/squashfs-root/

# 3. 使用Syft生成CycloneDX SBOM
syft dir:_firmware.bin.extracted/squashfs-root/ -o cyclonedx-json > sbom.json

# 4. 使用Grype进行漏洞匹配
grype sbom:sbom.json -o table

这里的关键是:Syft扫描的是解包后的文件系统,而不是原始固件二进制。对于没有文件系统的裸机固件,则需要结合字符串提取、符号表分析与组件指纹库进行识别,此时SBOM的完整性会下降,需要在HBOM中标注“软件成分不可完全枚举”的风险。

HBOM与SBOM在IoT固件中的集成方法

HBOM与SBOM的集成不是简单地把两个JSON文件放在一起,而是要在构建与发布流程中建立关联。推荐的做法是:在CI/CD流水线中,每次固件构建时同时生成SBOM,并将SBOM的哈希值写入HBOM的扩展字段;在设备出厂时,将HBOM与SBOM的引用写入设备的安全存储或OTA元数据中。这样,当某个CVE爆发时,可以通过“CVE→组件→SBOM→固件版本→HBOM→设备批次”快速定位受影响设备。

下图展示了HBOM、SBOM、固件构建与漏洞追溯之间的数据流关系:

HBOM / SBOM 与固件漏洞追溯数据流 HBOM(硬件物料清单) • 主控 MCU:STM32H743VIT6 • Wi-Fi 模组:ESP32-C3-MINI-1 • Flash:W25Q128JVSIQ • 传感器:SHT30-DIS • 批次号:LOT-2024-11 • SBOM 哈希:a3f8…c21d SBOM(软件物料清单) • 内核:Linux 5.10.120 • MQTT:mosquitto 2.0.11 • TLS:openssl 1.1.1k • 构建工具:buildroot 2023.02 • 格式:CycloneDX 1.5 • purl 标识:pkg:generic/openssl@1.1.1k 固件构建与发布 • CI/CD 流水线 • Syft 生成 SBOM • 固件版本:2.3.1 漏洞库与 VEX • NVD / OSV / GitHub Advisory • CVE-2023-0286(OpenSSL) • VEX 状态:affected / fixed 受影响设备定位 • 设备型号:GW-200 • 固件版本:2.3.1 • 批次:LOT-2024-11 硬件约束 软件成分 SBOM 比对 CVE 匹配 批次追溯 HBOM 提供硬件批次与 SBOM 哈希引用;SBOM 提供组件版本与 purl;两者联合实现 CVE 到设备批次的快速定位

漏洞追溯实战:从CVE到设备批次

假设某日公开了CVE-2023-0286,影响OpenSSL 1.1.1k及更早版本。追溯过程如下:

  1. 在漏洞库中确认受影响组件为openssl@1.1.1k,purl为pkg:generic/openssl@1.1.1k。
  2. 在SBOM仓库中检索包含该purl的SBOM文件,得到固件版本2.3.1。
  3. 通过HBOM中记录的“SBOM哈希”字段,确认该SBOM对应硬件批次LOT-2024-11,设备型号GW-200。
  4. 查询生产数据库,得到该批次已出货设备序列号范围,输出受影响设备清单。
  5. 根据VEX声明判断该漏洞在设备上下文中是否可利用:若OpenSSL仅用于已禁用的调试接口,则标记为not_affected;若用于MQTT over TLS,则标记为affected,触发OTA修复。

这个闭环的关键在于:SBOM必须与固件版本绑定,HBOM必须与批次绑定,且两者之间通过哈希或引用建立可验证的关联。如果SBOM是构建后补录的,或者HBOM没有记录SBOM引用,追溯就会断裂。

常见工程陷阱:许多团队在固件发布后才手工生成SBOM,导致SBOM与固件二进制不一致;或者HBOM只记录芯片型号,不记录批次与固件版本映射。这两种情况都会使漏洞追溯退化为“全量召回”,失去精准定位能力。

HBOM/SBOM工程检查要点

检查项 合格标准 常见问题
SBOM格式 CycloneDX 1.4+ 或 SPDX 2.3+,含purl与bom-ref 仅输出组件名称,无版本与唯一标识
HBOM字段 含型号、批次、固件版本、SBOM哈希 缺少批次与固件版本映射
生成时机 CI/CD构建阶段自动生成,与固件同版本 发布后手工补录,与二进制不一致
漏洞匹配 使用Grype/OSV-Scanner对SBOM自动扫描 仅依赖人工比对CVE列表
VEX声明 对每个受影响组件给出可利用性判断 所有CVE一律标记为affected,造成告警疲劳

对于IoT设备,HBOM与SBOM的工程化不是一次性任务,而是贯穿需求、选型、构建、测试、发布、运维的持续过程。只有把物料清单变成构建流水线的“副产品”而非“额外文档”,才能真正支撑供应链漏洞的快速追溯与精准响应。