收到某个 Java 组件的漏洞公告时,最耗时间的事情可能不是升级代码,而是确认:哪些服务用了它,具体版本是什么,线上运行的又是不是刚检查的那个包。SBOM,也就是软件物料清单,可以为这项核对提供结构化线索。
以下以 Spring Boot 3.3 的功能为说明基线。
把清单装进应用制品#
Spring Boot 3.3 支持通过构建插件生成 CycloneDX 清单,将清单装入可执行 JAR,并提供可选择暴露的 Actuator 端点。标准生成路径为 META-INF/sbom/application.cdx.json。这些能力有助于把清单与产物放在一起,不等于只引入框架就已经自动完成所有配置。
清单用于描述软件组件等信息。它回答的是“由什么组成”,漏洞判断还需要相应的漏洞信息与分析过程。把清单文件生成出来,只是依赖可追溯的一步。
为什么只查当前 pom.xml 不够#
假设一个测试服务在提交 A 构建后上线,开发分支随后升级了依赖,但提交 B 还没有部署。此时查看开发分支里的版本,只能说明准备构建什么,无法证明线上已经更新。
间接依赖也会让人工核对变难。业务代码只声明一个框架组件,实际打包时还会解析其他依赖;构建配置、排除规则和版本管理可能影响最后结果。因此,问题应从“源码写了什么”转向“这个具体制品包含什么”。
这与使用 Jib 调整 JVM 参数涉及的交付边界相通:构建时写入的内容、容器启动方式和运行限制需要分别核对。SBOM 可以补充依赖证据,但不会替代运行时检查。
给制品和清单建立稳定关联#
可以在持续集成系统为每次发布保存一组关联信息:
| 信息 | 用途 |
|---|---|
| 源码提交标识 | 解释构建输入属于哪个版本 |
| 构建任务标识 | 找到当次依赖解析与打包日志 |
| JAR 摘要值 | 确认核对的是同一个应用制品 |
| SBOM 文件及其摘要值 | 固定当次清单内容 |
| 容器镜像摘要 | 对应部署使用的镜像内容 |
这是一种记录设计,不是某个标准要求的固定字段。重点是能从运行镜像找到对应清单,也能反向确认清单属于哪个构建。仅使用 latest 一类可变标签,无法单独完成这项关联。
如果重跑同一个提交得到不同依赖,也应保留各次构建的记录,不能因为提交号一样就覆盖旧清单。排查问题需要知道当时交付了什么,而不是事后重新构建出了什么。
还应考虑回退。服务回到旧镜像时,对应清单也应切换到旧构建记录,不能让管理页面继续显示最新分支的依赖。发布台账如果只保存一个可覆盖的“当前版本”,就难以解释故障发生时究竟运行了什么。
因此,可以把发布事件单独记录为“环境、时间、镜像摘要、构建标识”的关联,再根据镜像定位清单。清单负责描述制品,发布记录负责描述运行变化,两者各自保留历史,后续定位才有依据。
本地检查可以从打包文件开始#
在按对应版本配置了生成插件之后,可以先检查产物中是否确实包含清单。以下命令中,target/demo.jar 是待替换的文件名:
jar tf target/demo.jar
unzip -p target/demo.jar META-INF/sbom/application.cdx.json第一步看文件是否存在,第二步才读取内容。找不到时先检查构建是否运行了相应插件、当前查看的是普通 JAR 还是打包后的可执行 JAR,以及资源是否真正进入最终产物。不要直接通过添加一份手写依赖列表来掩盖生成失败。
检查内容时,挑选应用中确定使用的一个组件,核对名称和版本;再选一个间接依赖,确认它是否被记录。测试用依赖是否属于交付范围,也应结合插件配置核实,不能默认清单里每个条目都会在生产加载。
Actuator 端点是读取入口#
sbom 端点可以提供应用清单;端点启用、通过 HTTP 暴露与访问授权是不同事项。Spring Boot 3.3 默认只通过 HTTP 暴露健康端点,其他管理端点需要单独配置访问范围。
如果运维确实需要通过应用读取清单,可以为测试管理入口选择暴露 sbom,然后分别验证有权限与无权限的访问行为。不要把暴露所有 Actuator 端点当作排障捷径。
另一种更简单的路径是在交付仓库保存清单,由发布系统提供查询。两种方式解决的问题不同:制品仓库方便审计发布历史,运行端点便于核对某个实例提供的内容。无论采用哪一种,都需要把记录关联到真实运行镜像。
一份应用清单不等于整个容器清单#
可以把范围拆成三层看:应用依赖、JVM 及运行环境、基础镜像中的系统组件。只生成 Maven 依赖清单,不能据此宣称操作系统包也已经检查。
例如应用依赖没有某个压缩库,并不意味着基础镜像中不存在同名系统组件。反过来,扫描镜像时看到的条目,也可能不是业务应用直接引用的 Java 包。定位公告影响时,组件生态、版本与所属层次要一起匹配。
给每份清单写清范围,有助于减少误解。可以将应用清单与镜像扫描记录一同归档,但不应把两者简单拼接后就声称覆盖全部运行环境。覆盖边界需要由实际工具配置和检查结果说明。
收到漏洞公告后,怎样使用这些记录#
先确定公告中的组件和版本范围,再用清单找候选服务;接着核对部署镜像是否属于候选构建。找到依赖是风险分析入口,不能直接推断某个接口一定可被攻击,也不能因为没有直接调用该包就自动判定不受影响。
处理后,应验证升级产物的清单发生了预期变化,并核对对应镜像已经部署。若旧副本仍在运行,源码更新和构建成功都不能算整改完成。无法确认的实例应列为待核对项,保留明确状态。
也可以定期做一次演练:随意选择一个组件,要求团队从组件名追到运行实例,再从一个实例追到构建记录。如果这条链路中断,就说明还有交付信息需要补齐。
按项目版本配置生成工具#
实际项目应使用符合自身维护策略的 Spring Boot 与构建插件版本,按对应版本文档配置,不能把历史插件版本照搬到新项目。
SBOM 最有价值的地方,是让依赖判断落在具体制品上。清单生成、制品匹配、运行版本与整改结果连起来之后,团队才更容易回答“我们是否受影响”和“修复是否已经交付”。
参考来源#
- Moritz Halbritter,《SBOM support in Spring Boot 3.3》,Spring,2024-05-24。
- Spring Boot 文档维护者,《Endpoints》,3.3 系列参考文档。
- CycloneDX 项目,《Software Bill of Materials (SBOM)》,官方能力说明。
