如何生成 SBOM?
解读
在国内 Rust 岗位面试中,SBOM(Software Bill of Materials,软件物料清单) 已不再是“加分项”,而是合规硬门槛:网信办《关键信息基础设施安全保护条例》、工信部《软件供应链安全三年行动计划》均要求上线系统必须提供可追溯的第三方组件清单。Rust 项目依赖链深、静态链接多,cargo 默认只生成 Cargo.lock,无法直接满足国内监管对“名称-版本-许可证-哈希-漏洞”五元组的格式要求。面试官问“如何生成 SBOM”,核心想考察两点:
- 你是否理解国内监管侧重点(许可证合规、漏洞闭环、国产密码算法替换);
- 能否在不破坏 Cargo 工作流的前提下,自动化输出符合 SPDX/ CycloneDX 标准、且能被信通院“铸基”平台、奇安信、悬镜等国产 SCM 工具识别的文件。
知识点
- Cargo 元数据接口:
cargo metadata --format-version 1输出完整依赖图,包含 source、checksum、features。 - 国内常用 SBOM 规范:
- CycloneDX 1.5(xml/json):信通院白名单工具链原生支持,可携带“国产密码算法替换标记”扩展字段。
- SPDX 2.3(tag-value/json):工信部抽检模板指定格式,需额外填充“下载位置”与“版权所有”字段。
- Rust 生态工具:
cargo-cyclonedx:官方插件,一键生成 CycloneDX,支持 workspace;需加 --all-features 防止遗漏条件编译依赖。cargo-sbom(github.com/rust-secure-code/cargo-sbom):输出 SPDX,但默认不填充国内要求的“漏洞编号”字段,需二次加工。syft0.90+:支持cargo-auditable注入的 ELF 指纹,可在二进制阶段补全“静态链接时实际进入的依赖”,解决“源码 SBOM 与交付物不一致”的审计痛点。
- 许可证合规:Rust 依赖常带
MIT OR Apache-2.0双许可,需用askalono-cli扫描并人工确认最终选用条款,否则 SPDX 字段LicenseConcluded会被监管打回。 - 漏洞闭环:
cargo-audit输出 JSON,通过jq把 advisory-id 注入 CycloneDX 的 vulnerabilities 节点,满足《信息安全技术 软件供应链安全要求》GB/T 43698-2024 的“漏洞可追溯”条款。 - CI 集成:GitLab 国内私有化实例、Gitee Go、以及各大银行自研 Jenkins 均支持上传 SBOM,需在
.gitlab-ci.yml里把 SBOM 文件作为artifacts:reports:cyclonedx上传,供 SCM 门禁比对基线。
答案
在工程实践中,我采用“源码 + 二进制双通道”方案,保证交付给监管和客户的 SBOM 与最终运行镜像 100% 一致,步骤如下:
- 源码阶段:
生成cargo install cargo-cyclonedx --version 0.4.0 cargo cyclonedx --all-features --output-cdx-jsonbom.json,此时已包含所有 crates 的 name、version、checksum、license 表达式。 - 许可证精修:
用 Python 脚本把askalono crawl --format json . > license-map.jsonlicense-map.json的结论回填到bom.json的licenses节点,确保LicenseConcluded字段与国产白名单匹配;若发现GPL-3.0等高风险许可,立即触发 MR 阻塞。 - 漏洞注入:
这样 SBOM 里每个组件都携带cargo audit --json > audit.json jq -s '.[0] * {vulnerabilities: .[1].vulnerabilities}' bom.json audit.json > bom-vuln.jsonvulnerabilities数组,满足监管“一组件一漏洞编号”要求。 - 二进制阶段:
在Cargo.toml中加入
重新编译后,使用 syft 扫描 ELF:[dependencies] auditable = { version = "0.7", features = ["serde"] }
对比源码 SBOM,若出现syft packages mybin --output cyclonedx-json@1.5 > bin-sbom.jsoncompiler_builtins或libc静态链接版本差异,以二进制结果为准,并在 MR 说明中记录差异原因。 - CI 上传:
将最终bom-vuln.json与bin-sbom.json压缩为sbom.zip,通过银行内部 SCM 的/api/v1/sbom/upload接口上传,返回的traceId写入发布记录,完成合规闭环。
拓展思考
- 多语言混合仓库:若 Rust 作为动态库被 Go/Java 通过 CGO/JNI 调用,需用 syft 对整个容器镜像做聚合扫描,再与 Rust 侧 SBOM 做
component.bom-ref对齐,避免“重复计数”被监管扣分。 - 闭源依赖处理:国内厂商常提供
.a静态库但不给源码,可在 CycloneDX 的externalReferences里添加distribution-intake类型 URL,指向厂商在“信通院软件供应链安全服务平台”备案的编号,实现“黑盒组件”合规。 - 国密算法替换场景:当使用
ring0.16 时,默认带 AES-NI 指令集,若客户要求替换为国密 SM4,需自定义 feature 并重新编译,此时 SBOM 中properties节点需增加{"name": "crypto-algorithm", "value": "SM4-GM/T 0002-2012"},供后续密码合规抽检快速过滤。