3. 资产清点与软件物料清单

漏洞修复的第一道工序不是打补丁,而是回答一个更基础的问题:我们到底有哪些东西需要保护?如果资产台账本身不完整,后续的漏洞扫描、优先级排序和修复验证都会建立在错误的前提上。资产清点与软件物料清单(SBOM)正是解决这个问题的两套互补手段——前者回答“有哪些主机、容器、中间件”,后者回答“每个软件单元里到底装了哪些组件”。

资产台账的四层结构

工程实践中,资产台账通常按四层组织,每层有不同的采集方式和更新频率:

  • 主机层:物理机、虚拟机、云实例。关键字段包括主机名、IP、操作系统及版本、内核版本、所属业务、责任人、环境(生产/测试/开发)。采集方式以 CMDB 同步、云厂商 API 拉取、Agent 上报为主。
  • 容器层:镜像、容器实例、编排单元(Pod/Deployment)。关键字段包括镜像名与 digest、基础镜像、运行集群、命名空间、暴露端口。注意镜像必须用 digest 而非 tag 标识,因为 tag 可被覆盖。
  • 中间件层:Nginx、Tomcat、Redis、Kafka、数据库等。关键字段包括产品名、版本号、部署路径、配置文件位置、监听端口、依赖关系。
  • 第三方库层:语言级依赖,如 Java 的 jar 包、Python 的 wheel、Node.js 的 npm 包。这一层数量最大、变化最快,也是 SBOM 主要覆盖的对象。

四层之间不是孤立的:一个主机上运行多个容器,一个容器里打包了中间件和第三方库。台账必须保留这种包含关系,否则漏洞出现时无法回答“这个 CVE 影响了哪些主机”。

SBOM 的生成:从构建产物反推组件

SBOM(Software Bill of Materials)是软件组件的结构化清单,主流格式有 SPDX 和 CycloneDX。生成方式分两类:

构建时生成是最可靠的方式。在 CI 流水线中,构建完成后立即对产物做成分分析。以 Java 项目为例,使用 CycloneDX Maven 插件:

<plugin>
  <groupId>org.cyclonedx</groupId>
  <artifactId>cyclonedx-maven-plugin</artifactId>
  <version>2.7.9</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals><goal>makeAggregateBom</goal></goals>
    </execution>
  </executions>
</plugin>

执行 mvn package 后会在 target/ 下生成 bom.json,其中每个组件包含 name、version、purl(包唯一标识,如 pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1)和依赖关系。purl 是后续与漏洞库关联的关键字段。

运行时生成用于补充构建时无法覆盖的场景,比如容器镜像中通过 apt 安装的系统包。可用 Syft 对镜像做扫描:

syft registry.example.com/app:1.4.2 -o cyclonedx-json > sbom.json

生成的 SBOM 应随镜像一起存入制品库,并在镜像标签旁记录 SBOM 的 digest,保证“镜像—SBOM”一一对应、不可篡改。

资产与漏洞的关联方法

SBOM 本身不包含漏洞信息,它只提供“组件清单”。关联漏洞需要三步:

  1. 组件标识归一化:把 SBOM 中的 purl 或 CPE 与漏洞库(NVD、OSV、厂商公告)中的受影响组件标识对齐。purl 的 type/namespace/name@version 结构比 CPE 更精确,优先使用。
  2. 版本区间匹配:漏洞库通常给出受影响版本范围,如 >=2.0.0, <2.17.0。将 SBOM 中的版本号代入区间判断,注意语义化版本比较不能按字符串排序(2.9.0 小于 2.10.0)。
  3. 传播到资产:通过“镜像 digest → 容器 → Pod → 主机”的包含链,把组件级漏洞扩散到主机级资产,形成“受影响资产列表”。

下面这张图展示了从资产采集到漏洞关联的完整数据流,以及四层资产与 SBOM 之间的包含关系:

资产台账四层 主机层 物理机 / VM / 云实例 容器层 镜像 digest / Pod 中间件层 Nginx / Redis / Kafka 第三方库层 jar / wheel / npm SBOM 生成 构建时生成 CycloneDX Maven mvn package 运行时生成 Syft 扫描镜像 syft -o cyclonedx-json SBOM 制品 bom.json + digest 漏洞关联 漏洞库 NVD / OSV / 厂商公告 purl 匹配 版本区间判断 受影响资产 主机 + 容器 + 组件 purl 关联结果:CVE-2024-XXXX → log4j-core@2.14.1 → 镜像 app:1.4.2 → 主机 web-03 输出:受影响资产列表 + 修复优先级 组件 资产层 SBOM 生成 漏洞关联 关联结果

台账维护的三个关键约束

唯一标识不可变:主机用资产 ID,镜像用 digest,组件用 purl。任何一层用可变标识(如 IP、tag、文件名)做主键,都会在资产变更时产生关联断裂。

更新触发条件明确:主机层在 CMDB 变更时同步;容器层在镜像推送时更新;SBOM 在每次构建时重新生成。不要依赖定期全量扫描,因为扫描周期内新部署的资产会成为盲区。

关联链可追溯:从漏洞到资产的每一步都要能反向查询。例如给定 CVE 编号,能查出所有含该组件的镜像 digest,再查出运行这些镜像的容器和主机。这条链的完整性决定了修复工单能否准确派发。

实践建议:初期不必追求四层全部自动化。可以先从容器层和 SBOM 入手,因为容器镜像天然适合做成分分析,且 SBOM 生成可以嵌入 CI 流水线。主机层和中间件层可通过 Agent 或配置管理工具逐步补齐。关键是先建立“组件—镜像—主机”这条最小关联链,再向两端扩展。

资产清点和 SBOM 不是一次性项目,而是持续运行的工程能力。台账的准确率直接决定漏洞修复的命中率——漏掉一个资产,就可能漏掉一个正在被利用的漏洞。