2、镜像供应链安全基础:软件供应链攻击模型、镜像篡改与投毒风险分析

镜像供应链安全是云原生安全体系中最薄弱的环节之一。攻击者不再直接攻击运行时容器,而是将恶意代码植入镜像构建、分发或部署的任意一个上游环节,形成“一次投毒、扩散”的供应链级攻击。理解攻击模型与风险类型,是构建有效安全水位巡检的前提。

2.1 软件供应链攻击模型:从开发到部署的四个攻击面

镜像供应链的生命周期可抽象为四个连续阶段,每个阶段都存在独特的攻击向量。下表总结了各阶段的核心风险与典型攻击手法:

阶段 攻击面 典型攻击手法 影响范围
开发阶段 源代码、依赖库、构建脚本 依赖混淆、恶意NPM/PyPI包、Git泄露密钥 单个项目或组织
构建阶段 Dockerfile、基础镜像、CI/CD管道 基础镜像投毒、构建缓存污染、CI凭证窃取 镜像仓库内所有派生镜像
分发阶段 镜像仓库、传输通道、镜像签名 镜像篡改、中间人攻击、仓库凭证泄露 所有拉取该镜像的集群
部署阶段 Kubernetes Admission、策略引擎 运行态镜像替换、恶意Sidecar注入、未验证镜像部署 目标集群及关联服务
关键认知: 攻击者只需攻破四个阶段中的任意一个,即可将恶意镜像投递到生产集群。传统“运行时检测”无法防御构建阶段就已植入的后门。

2.2 镜像篡改与投毒风险深度分析

镜像篡改与投毒是供应链攻击中最常见、危害最大的两类风险。以下从技术实现角度拆解其攻击原理与检测难点。

2.2.1 镜像篡改:分层结构与摘要验证的盲区

Docker 镜像由多层只读文件系统叠加而成,每层对应一个 Layer ID(基于内容哈希)。镜像清单(Manifest)记录了所有层的哈希和大小。篡改攻击通常发生在以下场景:

  • 中间人替换层: 在镜像拉取过程中,攻击者拦截 Registry 响应,替换 Manifest 中指向的某个 Layer Blob 为恶意层。若客户端未验证 Manifest 签名,则拉取到篡改镜像。
  • 仓库侧篡改: 攻击者获得 Registry 写权限后,直接修改已有镜像的 Tag 指向另一个恶意 Manifest,或覆盖某个 Layer 的内容。
  • 本地缓存投毒: 在共享 CI Runner 或开发机中,攻击者篡改本地 /var/lib/docker 下的层缓存,使后续构建引用恶意层。

传统防护依赖 docker pull 后的摘要(Digest)比对,但摘要本身若未通过可信渠道分发,则比对无意义。这是 Sigstore 引入 无密钥签名 的核心动因——将摘要签名与 OIDC 身份绑定,使篡改行为可被加密验证。

2.2.2 镜像投毒:从基础镜像到依赖链的全面渗透

镜像投毒指攻击者将恶意代码嵌入镜像的某个合法组件中,使其在容器启动时自动执行。常见投毒路径包括:

  1. 基础镜像投毒: 攻击者上传带有后门的“官方”镜像(如 node:18-alpine-backdoor),或攻破官方镜像构建管道,在合法基础镜像中植入挖矿程序。
  2. 依赖包投毒: 通过 依赖混淆(Dependency Confusion)或 类型劫持(Typosquatting)将恶意包注入 requirements.txt 或 package.json。构建时包管理器自动下载恶意版本。
  3. 多阶段构建残留: 构建阶段使用了包含敏感文件(如 SSH 密钥、云凭证)的中间镜像,但未在最终镜像中清理干净,导致凭证泄露。
  4. 运行时数据投毒: 攻击者通过挂载卷或环境变量注入恶意配置,使容器启动后加载攻击者控制的动态库或二进制文件。
风险警示: 2023 年某知名云原生项目因基础镜像中的 libcurl 被替换为带后门的版本,导致所有下游用户容器在发起 HTTPS 请求时泄露环境变量。该事件持续 72 小时才被发现,影响超过 10 万个生产容器。

2.3 镜像供应链攻击链全景图

下图展示了从代码提交到容器运行的完整攻击链,以及每个环节可能被植入的恶意载荷类型:

镜像供应链攻击链全景图 镜像供应链攻击链全景图 开发阶段 源代码 / 依赖库 构建阶段 Dockerfile / CI管道 分发阶段 镜像仓库 / 传输 部署阶段 K8s Admission 攻击者只需攻破任意一个阶段,即可将恶意镜像投递到生产集群 典型载荷 • 依赖混淆包 • 硬编码密钥 • 恶意Git提交 典型载荷 • 基础镜像后门 • 构建缓存投毒 • CI凭证窃取 典型载荷 • 镜像层替换 • Tag劫持 • 中间人篡改 典型载荷 • 未验证镜像 • Sidecar注入 • 运行态替换 安全防线:Sigstore 无密钥签名 + 策略引擎 + 运行时验证 在构建阶段签名 → 分发阶段验证签名 → 部署阶段强制策略 💡 安全水位巡检目标:在每个阶段设置可量化的检测点,确保镜像从构建到部署的完整可追溯性

2.4 镜像供应链安全水位巡检的核心指标

基于上述攻击模型,安全水位巡检需要覆盖以下六个关键维度。每个维度对应一个可量化的检查项:

巡检维度 检查项 高风险阈值 理想水位
基础镜像溯源 基础镜像是否来自可信源且版本锁定 使用 latest 标签或非官方仓库 使用摘要(Digest)锁定且经过签名验证
依赖库安全 是否存在已知漏洞或混淆包 存在 CRITICAL 级别 CVE 或未审计的第三方包 SBOM 生成 + 漏洞扫描通过 + 依赖锁定
构建过程完整性 CI/CD 管道是否具备防篡改能力 无构建日志审计、无签名步骤 构建产物自动签名 + 构建环境可复现
镜像签名覆盖率 仓库中已签名的镜像比例 签名覆盖率 < 80% 100% 镜像强制签名(含基础镜像)
部署策略强制 K8s 是否验证镜像签名后再调度 Admission 未启用签名验证 策略引擎拒绝未签名或签名失效的镜像
运行时一致性 运行容器是否与已签名镜像一致 容器哈希与签名摘要不匹配 运行时持续验证 + 异常告警
巡检建议: 建议将上述六个维度纳入每周自动巡检脚本,输出“安全水位评分卡”。评分低于 60 分的集群应立即阻断新镜像部署,直至修复完成。

2.5 从攻击模型到 Sigstore 集成:为什么需要无密钥签名?

传统镜像签名方案(如 Docker Content Trust)依赖中心化密钥管理,存在以下固有缺陷:

  • 密钥泄露风险: 签名私钥一旦泄露,攻击者可对任意镜像签发合法签名。
  • 密钥轮换成本高: 每次轮换需要重新签名所有历史镜像,操作复杂且易出错。
  • 身份绑定弱: 签名仅证明“某个密钥签过”,无法关联到具体的开发者或 CI 流水线身份。

Sigstore 通过 无密钥签名(Keyless Signing)解决了上述问题:

  1. 签名者使用 OIDC 身份(如 GitHub OAuth、Google 邮箱)向 Sigstore 的 Fulcio CA 申请短期证书。
  2. 证书绑定签名者的身份信息,签名操作在内存中完成,私钥不落盘。
  3. 签名后的镜像摘要和证书被记录到 Rekor 透明日志中,任何人都可公开审计。

这种设计使得攻击者即使攻破了 CI 管道,也无法伪造历史签名,因为每次签名都需要实时 OIDC 认证,且透明日志提供了不可篡改的审计线索。