软件供应链安全:SBOM、签名与依赖漏洞治理

纵深防御软件供应链:SBOM 生成与审计(Syft/Grype/CycloneDX)、镜像与产物签名(cosign/Notary)、依赖策略与锁文件、SCA 扫描进流水线门禁、SLSA 与零信任发布、CVE 应急响应。

“生产环境的组件,一半不是你写的”——这就是软件供应链安全的现实。一次上游投毒、一次依赖劫持,能让整个组织的基础设施瞬间失守。本文按防御链展开:SBOM 生成(Syft/CycloneDX)→ 漏洞审计(Grype/osv-scanner)→ 产物签名(cosign)→ 依赖与锁文件治理 → SCA 进流水线门禁 → SLSA 零信任发布 → CVE 应急响应,每步都给出现成命令与配置。


目录


1. 供应链攻击形态与威胁模型

1.1 三类主要攻击形态

上游投毒:往开源依赖/基础镜像植入恶意代码(event-stream、ua-parser-js)
构建链污染:攻破 CI 或镜像仓库替换产物(SolarWinds 类)
依赖劫持:typosquatting(近似包名)、同名抢注、版本回滚攻击

1.2 攻击路径示例

恶意 npm 包(名字像合法包)→ 开发者安装 → CI 构建时执行窃密脚本 →
窃取部署凭证 → 提权到镜像仓库/云账号。攻击往往发生在"没人检查"的构建环节

1.3 信任链与威胁模型

信任点攻击方式防御手段
上游源码提交被篡改/维护者失陷签名校验 + 关注维护者动态
依赖包投毒/劫持锁文件 + 哈希校验 + SCA
构建环境凭证窃取/替换产物隔离 Runner + 短时令牌
镜像仓库未授权写入cosign 签名 + 仓库 RBAC
部署环境运行被替换镜像准入控制验证签名

2. SBOM 生成:Syft 与 CycloneDX

2.1 SBOM 是什么

SBOM(软件物料清单)= 机器可读的组件清单,回答"这个产物里有什么"
标准格式:SPDX 与 CycloneDX;用途:出漏洞定位受影响镜像、合规审计、供应链透明

2.2 用 Syft 生成 SBOM

# 扫镜像生成 CycloneDX SBOM
syft packages registry:5000/shop/api:v1.2.3 -o cyclonedx-json > sbom.api.json
# 扫构建目录(未打包前)
syft packages dir:dist/ -o spdx-json > sbom.spdx.json
# 校验 SBOM 语法(防格式错误导致审计工具拒读)
cyclonedx validate --input-file sbom.api.json

2.3 SBOM 随制品保存

SBOM 要随产物归档:镜像 → cosign attach sbom 写入 Registry;包 → 进制品库;无 SBOM = "成分未知,禁止上线"

3. SBOM 审计与漏洞匹配:Grype

3.1 Grype 匹配漏洞

# 直接扫镜像(内部先生成 SBOM 再匹配漏洞库)
grype registry:5000/shop/api:v1.2.3 --only-fixed --fail-on high
# 扫已有 SBOM 文件(审计外部给的清单)
grype sbom:sbom.api.json -o json > grype-report.json

3.2 关注"新引入漏洞"而非总数

全量漏洞数是存量负债,真正危险的是"本次新引入的漏洞":
  以基线(上周扫描结果)做 diff,新出现 CRITICAL/HIGH 直接拦截构建;
  存量漏洞按修复计划 + 风险接受管理,不阻塞一切发布
基线 diff:osv-scanner --format json -r . > current.json,对比上一版本

3.3 Google OSV 与全语言覆盖

# osv-scanner:统一用 OSV 数据库覆盖 npm/pypi/go/maven/rust
osv-scanner -r --lockfile-locations package-lock.json,poetry.lock,go.sum
# 优点:CVE 之外还能发现 GitHub 安全公告、恶意包(malicious)条目

4. 镜像与产物签名:cosign 与 Notary

4.1 cosign 签名

# 生成密钥对(或用 KMS 保管私钥)
cosign generate-key-pair
# 给镜像签名(签名作为 OCI Artifact 存进仓库)
cosign sign --key cosign.key registry:5000/shop/api:v1.2.3
# 验证签名(部署/拉取前)
cosign verify --key cosign.pub registry:5000/shop/api:v1.2.3

4.2 签名 + SBOM 一起附加

# 把 SBOM 作为 attestation 附加到镜像
cosign attach sbom --sbom sbom.api.json \
  registry:5000/shop/api:v1.2.3

# 校验镜像摘要(防仓库被改写后签名仍匹配)
cosign verify-attestation --key cosign.pub \
  registry:5000/shop/api@sha256:...

4.3 部署时验证签名

签名必须在"部署时验证"才有效:K8s 用 Kyverno/cosign 准入控制器,强制镜像
  带有效签名才允许创建 Pod;CI 发布前强制 verify,不通过即发布失败
Notary(Docker 早期方案)已基本被 cosign 取代,新项目优先 cosign

5. 依赖策略与锁文件治理

5.1 锁文件是底线

锁文件 = 记录精确版本 + 哈希,防止"昨天构建和今天构建不一样"
  npm → package-lock.json / Python → poetry.lock / Go → go.sum / Java → gradle.lockfile
门禁:仓库必须提交锁文件,CI 构建若产生锁文件 diff → 拦截

5.2 依赖引入策略

最小依赖:新引入需说明理由,控制依赖树深度
固定版本:禁用浮动版本(^1.2.3、latest),只用精确版本
许可合规:许可证纳入审查(Copyleft 需评估);只用官方源 + 校验哈希

5.3 自动升级与人工审批

# Renovate:patch 自动合入;major 人工审;升级 PR 必须先过 SCA 门禁
{
  "extends": ["config:recommended"],
  "automerge": true,
  "packageRules": [
    { "matchUpdateTypes": ["major"], "automerge": false },
    { "matchUpdateTypes": ["patch"], "automerge": true }
  ]
}

6. SCA 扫描进流水线

6.1 SCA 工具对比

工具覆盖数据源特点
Trivy镜像+SBOM+依赖多源Go 单二进制,CI 友好
GrypeSBOM+镜像多源与 Syft 同生态
osv-scanner锁文件OSV含恶意包告警
Snyk依赖+IaC商业库覆盖全但付费

6.2 扫描进流水线门禁

# GitHub Actions:供应链扫描步骤
steps:
  - uses: actions/checkout@v4
  - name: SBOM
    run: syft dir:. -o cyclonedx-json > sbom.json
  - name: Scan
    run: grype sbom:sbom.json --fail-on high --only-fixed
  - name: Secret guard
    run: gitleaks detect --exit-code 1
  - name: Gate
    run: |
      python ci/supply_gate.py --sbom sbom.json \
        --max-new-critical 0 --max-new-high 0

6.3 门禁分级

CRITICAL 新引入 → 拦截;HIGH 新引入 → 拦截;中危/存量 → 台账按 SLA 修复
恶意包(OSV malicious)→ 无条件拦截 + 排查是否已被使用

7. 零信任发布与可溯源

7.1 零信任发布四要素

身份可信:构建者身份可验证;产物可信:镜像带签名部署时验证
成分可信:SBOM 完整且无高危漏洞;过程可信:构建过程可审计(谁/何时/何代码)

7.2 SLSA 等级实践

SLSA 由低到高 L1~L3:L1 构建有文档+产物带哈希;L2 托管构建+签名+防篡改;
  L3 不可伪造来源证明(provenance)+隔离构建
多数组织目标 L2:托管 CI + cosign 签名 + provenance 记录

7.3 来源证明(Provenance)

# 记录"这段镜像由哪个仓库哪个 commit 构建"(概念)
cosign attest --predicate provenance.json --key cosign.key \
  registry:5000/shop/api:v1.2.3
# 事后审计:verify-attestation 拉出 provenance 核对 commit 与构建者

8. 合规与应急响应

8.1 合规要求

典型要求:随时提供每个产物的 SBOM、证明产物来源与签名者
  (美国 EO 14028、欧盟 CRA、各地关基要求)→ SBOM 归档 + 签名留痕

8.2 CVE 应急响应流程

重大漏洞公布(如某日志库 RCE):
  1. SBOM 全量匹配受影响产物 → 2. 按暴露面排序(公网 > 内网 > 离线)
  3. 升级依赖 → 重建 → 过门禁 → 发布 → 4. 验证回写台账
  无法升级的组件做缓解措施(WAF/禁用功能)

8.3 演练与度量

每季度"模拟 log4j"演练:公布假 CVE,考核定位/修复发布时长与沟通顺畅度
度量指标:MTTD(发现时长)、MTTR(修复时长)、新漏洞拦截率

9. 案例与最佳实践

9.1 真实案例

某中型电商(概念案例):某 npm 依赖爆出 RCE,两天找不到用了哪些镜像
改造:syft 生成 SBOM + cosign 签名归档 → Grype 扫 SBOM 进门禁 → 验签准入
第二次 CVE:10 分钟筛出 3 个受影响镜像,2 小时完成修复发布

9.2 最佳实践 Checklist

□ 每个可发布产物强制生成 SBOM(Syft/CycloneDX)并归档
□ Grype/osv-scanner 扫 SBOM,新引入高危漏洞拦截
□ 镜像/包全部 cosign 签名,部署时准入验证签名
□ 签名与 SBOM 作为 attestation 随镜像进 Registry;仓库强制锁文件
□ Renovate/Dependabot 自动升级 + 人工审批 major
□ SCA 扫描进流水线门禁,恶意包无条件拦截
□ 构建过程记录 provenance(SLSA L2 起步)
□ 建立 CVE 应急响应流程,季度演练

9.3 常见坑

坑现象对策
SBOM 生成不归档应急时找不到随产物进制品库
只扫不签名仓库被改无法发现cosign 签名 + 部署验签
全量漏洞当门禁存量债阻塞所有发布区分新引入 vs 存量
锁文件不入库构建结果漂移CI 强制锁文件 diff 检查
签名只在 CI 验部署环节被绕过准入控制器部署时验签
只防 npmJava/Go/镜像漏掉全语言 osv-scanner 覆盖

小结

供应链安全 = SBOM 生成(Syft)→ 漏洞审计(Grype/osv-scanner)→ 产物签名(cosign)→ 依赖锁文件治理 → SCA 流水线门禁 → SLSA 零信任发布 → CVE 应急响应。核心三件事:知道产物里有什么(SBOM)、验证产物是谁造的(签名)、阻止坏成分进线(门禁)。从"构建时生成 SBOM + 签名 + 新漏洞拦截"这条最小链起步,再逐步补全 provenance 与应急演练,就能把供应链从"黑箱"变成"可审计的清单"。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「DevOps」更多文章

  1. CI/CD 流水线安全:供应链攻击防御与硬编码凭证治理
  2. 多云与混合云工程:成本、身份与统一编排
  3. AI 辅助运维:GenAI 在事件响应与排障中的实践