引言
2020年SolarWinds事件震惊全球——攻击者通过入侵Orion平台的构建服务器,将SUNBURST后门植入合法的软件更新包中,导致包括美国财政部、商务部在内的18000多个组织被渗透。2024年,XZ Utils压缩库的维护者艰辛争取信任后植入SSH后门,几乎影响全球所有Linux发行版。这两起标志性事件揭示了一个残酷现实:攻击者不再直接攻击你的软件,而是攻击你信任的软件是如何被构建的。
软件供应链安全(Software Supply Chain Security)已从一个小众安全话题演变为企业和国家安全的战略级议题。本文将深入分析供应链攻击的技术原理、防御框架和工程实践,帮助你在CI/CD流水线中建立可信防线。
一、软件供应链攻击面全景
1.1 攻击类型分类
根据Linux基金会和OpenSSF的定义,软件供应链攻击主要分为以下几类:
依赖混淆攻击(Dependency Confusion)——2021年Alex Birsan通过在企业私有包名称对应的公共仓库中发布更高版本的恶意包,成功入侵苹果、微软等大公司内网。当包管理器优先从公共仓库拉取更高版本时,恶意代码即在CI/CD环境中执行。
typosquatting攻击——攻击者在公共仓库中发布名称与流行包极其相似的恶意包(如将requests拼写为reqests)。npm审计数据显示,每年有数千个typosquatting包被发现。
构建系统入侵——直接攻击CI/CD服务器或构建工具链,在编译/打包阶段注入恶意代码。SolarWinds事件和XZ后门事件均属此类。
开发工具污染——篡改IDE插件、编译器或代码签名证书,使开发者在不知情的情况下产出含后门的软件。
12个关键攻击面
从源代码到生产部署,软件供应链涵盖开发者工作站→版本控制系统→依赖管理→CI/CD构建→制品仓库→部署编排→运行时环境等多个环节,每个环节均存在潜在攻击向。
二、核心防御框架:SLSA与Sigstore
2.1 SLSA框架(Supply Chain Levels for Software Artifacts)
SLSA(读作salsa)是Google牵头提出的软件供应链安全成熟度模型,定义了四个递进的安全等级:
| 等级 | 要求 | 防护效果 |
|---|---|---|
| L1 | 构建过程完全自动化并生成来源元数据 | 提供基本的可追溯性证明 |
| L2 | 使用版本控制托管的构建服务 + 签名来源 | 防范构建后篡改和中间人攻击 |
| L3 | 硬化的构建平台 + 经过审查的源代码 | 防范CI/CD平台级别的入侵 |
| L4 | 可重复构建 + 两人同行审查 | 提供最高级别的供应链完整性保证 |
目前大多数企业级项目可达到L2-L3水平,Google内部关键系统已实现L4。对于开源项目,L3是一个现实且有价值的目标。
2.2 Sigstore:让签名无处不在
Sigstore是Linux基金会托管的项目,解决了长期困扰软件行业的密钥管理难题。其三大核心组件分别为:
Cosign\——用于容器镜像和OCI制品的签名与验证,支持keyless模式(基于OIDC身份进行签名,无需管理长期密钥)。
Fulcio\——免费公共证书颁发机构,为代码签名提供短时效的X.509证书,自动绑定到OIDC身份(如GitHub Actions的workflow身份)。
Rekor\——透明的不可篡改日志,记录所有签名事件,提供第三方可审计性。
在GitHub Actions中集成Cosign仅需几行配置:
steps:
- uses: sigstore/cosign-installer@v3
- name: Sign container image
run: cosign sign --yes ${{ steps.build.outputs.digest }}
env:
COSIGN_EXPERIMENTAL: 1
三、工程实践:构建可信CI/CD流水线
3.1 依赖锁定与校验
所有依赖必须锁定具体版本,并通过多维度校验确保完整性:
锁定文件——使用package-lock.json(npm)、go.sum、requirements.txt with hashes、Cargo.lock等锁定依赖树。确保锁定文件本身受到版本控制保护,禁止手动修改。
哈希校验——在下载或安装依赖时强制验证加密哈希值。npm audit自动检查、Go modules的go.sum、Python的pip hash-checking mode均提供此能力。
镜像代理——使用私有依赖代理(如Artifactory、Nexus)缓存并审计所有外部依赖,避免直接从不可信的公共仓库拉取。代理还应提供漏洞扫描、许可证合规检查等能力。
3.2 构建环境安全
短暂(Ephemeral)构建环境——每次构建都在全新的、临时的虚拟机或容器中进行,构建完成后彻底销毁。这消除了构建环境被持久化攻击的可能性。GitHub Actions的默认行为、Google Cloud Build等均支持此模式。
最小权限原则——CI/CD服务账号仅拥有构建所需的最小权限。禁止使用在生产环境直接部署的令牌进行构建操作。为不同项目、不同环境的账号建立最小化的权限边界。
构建脚本不可变性——构建流程定义存储在版本控制的配置文件中(如.github/workflows/*.yml),禁止使用从外部URL动态获取的构建脚本。这防止了"构建脚本本身被攻击"的情况。
3.3 制品签名与验证
每次构建都签名——每个构建产物(容器镜像、二进制文件、包)都应使用Cosign进行签名,并将签名信息记录到Rekor透明日志。
策略驱动的部署验证——在部署端使用Kyverno、OPA/Gatekeeper等策略引擎,仅允许部署经过正确签名且来自可信来源的容器镜像。拒绝任何未签名或签名来源不明的制品进入生产环境。
SBOM(软件物料清单)生成——使用Syft或SPDX工具在构建时自动生成SBOM,记录所有直接和间接依赖。SBOM应随制品一起签名和分发,为漏洞管理和合规审计提供数据基础。
3.4 漏洞管理与快速响应
建立依赖漏洞的持续监控和自动化修复流程:
SCA扫描——在CI/CD中集成Snyk、Trivy、Grype等SCA(软件成分分析)工具,每次代码提交时扫描依赖漏洞。对高危漏洞设置构建阻断阈值。
自动化修复——使用Dependabot或Renovate自动提交依赖更新PR,配合CI测试自动合并低风险修复。对重大版本更新则通知开发者手动审查。
漏洞影响分析——当新的CVE披露时,利用SBOM数据(如通过VEX/Vulnerability Exploitability eXchange)快速判断组织内哪些项目实际受到影响,减少"漏洞警报疲劳"。
四、组织级供应链安全治理
1. 建立内部可信基础镜像仓库
2. 对关键依赖建立内部_vendor_镜像和审批流程
3. 引入第三方安全审计(尤其是对外提供的开源项目)
4. 为开源维护者提供可持续性支持(XZ事件的根本原因之一是关键基础设施的维护者严重不足)
五、未来趋势
S2C2F成熟度模型——CNCF发布的Secure Software Factory(S2C2F)正在成为云原生领域供应链安全的事实标准,与SLSA互补。
内存安全语言迁移——美国ONDI战略明确要求关键基础设施向Rust、Go等内存安全语言迁移,从根源上消除70%以上的安全漏洞。
AI辅助审计——利用大语言模型分析依赖变更中的异常模式,自动检测潜在的供应链攻击(如XZ后门中的混淆技术)。
结语
软件供应链安全不是一次性的项目,而是需要融入日常工程实践的持续过程。从今日开始审视你的CI/CD流水线:你的依赖是否锁定?你的构建是否短暂?你的制品是否签名?这三个问题的答案,决定了你的软件供应链处于哪个成熟度水平。
正如安全界的古老格言所说:"安全不是一个产品,而是一个过程。"在供应链安全领域尤其如此——它关乎的不是你自己的代码有多安全,而是你信任的那些代码的来源有多可信。

发表评论 取消回复