10.1 依赖与 SBOM:知道制品里真正有什么
上一章把检查结果绑定到交付 digest。本章沿着这个 digest 继续追问:包里实际装了什么,以及谁能说明它从哪里来。
软件供应链不只包含开源包,还包含源码托管、构建脚本、编译器、基础镜像、CI action、插件、包仓库和发布渠道。SBOM 解决“制品由哪些组件构成”,不能单独证明这些组件可信或构建过程未被篡改。
依赖图比清单更接近真实风险
application
├── direct dependency A
│ └── transitive dependency C
├── generated client B
├── base image packages
└── bundled runtime / native libraryManifest 表达开发者请求的范围,lockfile 通常记录解析后的精确版本,部分生态还记录完整性摘要;并非每种锁文件都具有相同保证。最终制品又可能因打包、裁剪和动态下载不同。三个视角都需要,不能只扫描 package.json 或 pom.xml。
安装时禁用不必要的 lifecycle script,使用受控 registry/mirror,验证 checksum/signature,固定 CI action 与基础镜像 digest。Dependency confusion 防护还要确保私有命名空间不会回退到公共同名高版本包。
SBOM 绑定具体制品
一份可操作 SBOM 应关联 artifact digest,并包含足够的组件身份、版本、供应者、关系和生成工具信息。SPDX 与 CycloneDX 是常见格式;选择取决于生态和消费者,不要自创无法互操作的 JSON。
artifact sha256:abc...
contains package-url pkg:maven/...@version
dependsOn ...
generatedBy tool/version at timestamp扫描源目录生成的 SBOM 与最终容器 SBOM 可能不同。发布时应从最终 artifact 生成或核对,并对 fat JAR、静态链接、vendored source 和多阶段镜像做覆盖测试。
SBOM 质量需要验证
- completeness:最终制品中的组件是否被发现;
- correctness:名称、版本、PURL/CPE 是否准确;
- dependency relationships:直接与传递关系是否保留;
- freshness:是否绑定当前 digest,而非上次构建;
- integrity:SBOM 是否随制品签名/attestation 分发;
- availability:事件时能否按组件查询全部部署位置。
“生成了文件”不等于可用。可准备一个固定测试制品,内含已知应用库、基础系统包与手工放入的本地二进制,逐项核对 SBOM。删掉某组件或更新其版本后重建,SBOM 也应改变;无法识别的二进制应保留路径与摘要并标明未知,不能静默算作完整覆盖。
漏洞匹配需要上下文
CVE 匹配可能因生态命名、backport 和版本区间误判。操作系统发行版可能保留上游版本号而增加发行版 package revision 来回补修复;应检查发行版完整版本和安全公告,不能只比较上游 semver。库存在也不代表漏洞函数可达。
VEX 可以表达某产品对某漏洞的状态与理由,例如 not affected because vulnerable code is not present。VEX 必须有可验证生产者身份、精确产品/制品范围、分析依据和更新时间,不能成为批量“不可利用”的免责标签。
事件优先级结合在野利用、可达性、暴露面和数据影响。即便暂不可达,也要记录配置/feature 变化后重新评估的触发条件。
依赖更新是一项持续交付能力
小步、自动化更新比几年一次大升级更容易评审和回退。更新机器人应受变更策略约束:允许来源、版本范围、测试、changelog 和签名验证;不能因为“机器人提交”自动绕过评审。
无法维护的依赖应替换、隔离或删除。Fork 意味着团队接管补丁、发布和漏洞响应责任,不是把风险从 dashboard 上消失。
下一课回答这个 digest 是否由预期源码在受信构建平台产生。
参考资料
- SPDX, Specification
- CycloneDX, Specification