软件供应链安全

共 18 题
📑 题目列表 18 题
#
★★★

1. pnpm-lock.yaml 等锁文件如何保证依赖可复现,与 npm/yarn 锁文件在供应链防护上有何差异?

pnpm 的 pnpm-lock.yaml 等锁文件是如何保证依赖在多次安装中可复现的?与 npm 的 package-lock.json、yarn 的 yarn.lock 相比,在供应链防护上有何差异?

  • 锁文件锁定依赖版本与传递依赖的机制
  • 各包管理器锁文件的核心差异(resolved 地址、integrity 校验、内容寻址)
  • 锁文件在供应链防护中的作用与局限

锁文件的核心作用是锁定"依赖树"的精确版本,包括直接依赖与所有传递依赖(transitive dependencies),并记录每个包的下载地址(resolved)与完整性校验值(integrity,通常是 sha512 哈希),从而保证在任何环境 install 时都能得到完全相同的依赖树,实现可复现构建。npm 的 package-lock.json 与 yarn 的 yarn.lock 都基于每个包的版本与 integrity 记录;pnpm 的 pnpm-lock.yaml 与之不同,它采用内容寻址存储(content-addressable store),并在锁文件中记录 peer 依赖解析结果与不同 peer 组合下的快照,因而对依赖树结构更严格、更稳定。在供应链防护上,锁文件都通过 integrity 校验防止包被篡改或替换,但 pnpm 不会扁平化 node_modules(避免 hoisting 导致的依赖混淆),能更好地避免"幻影依赖"与依赖提权风险,从而更贴合供应链安全要求。

锁文件是"可复现"与"供应链完整性"的第一道防线:它把"版本选择"从运行时决策变成安装前的确定值,并通过 integrity 校验防范 registry 投毒或中间人替换。pnpm 的差异在于其非扁平化结构和对内容寻址的依赖,使其在供应链防护上更严格,但也要求团队理解其 peer 快照机制。

# 查看锁文件中某个包的完整性与来源地址
grep -A2 '"@vue/compiler-sfc"' package-lock.json
# pnpm 校验 store 完整性
pnpm store status
# 以冻结锁文件模式安装,不更新锁文件
pnpm install --frozen-lockfile
#
★★★

2. 如何在 Buildkite 等 CI 平台上落地供应链安全,即构建环境隔离、凭据保护与产物签名?

如何在 Buildkite 等 CI 平台上落地供应链安全,包括构建环境隔离、凭据保护与产物签名三个方面?

  • 构建环境隔离(隔离 agent、受控镜像、临时环境)
  • 凭据保护(最小权限、短期令牌、注入方式)
  • 产物签名(签名工具、公钥分发、验证)

在 Buildkite 上落地供应链安全主要通过三个层面:其一,构建环境隔离——使用隔离的 agent runner(如 agent 只允许执行受信任的 pipeline),通过 queue 将不同信任级别的构建分开,使用受控的构建镜像(锁定版本、不可变 tag),并尽可能用临时/一次性环境避免污染。其二,凭据保护——构建所需的密钥通过 Buildkite 的 secret 管理或外部 secret 后端(如 Vault、AWS Secrets Manager)注入,遵循最小权限原则,只授予构建确实需要的权限,优先使用短期令牌(如 OIDC 动态凭据)而非长期密钥,并避免在日志中泄露。其三,产物签名——构建完成后用 cosign/sign 等工具对产物(如镜像、二进制包)签名,公钥通过公开渠道分发,下游消费时用 cosign verify 校验签名与完整性,确保产物未被篡改。

CI 供应链安全的本质是"构建环境不可信"与"构建结果可信"之间的平衡:隔离确保一个 pipeline 的注入不影响其他构建,凭据的短期化与最小权限降低泄露面,签名则把信任从"构建过程"转移到"可验证的产物"。三者结合形成从环境到产物的完整信任链。

# Buildkite pipeline 中注入短期凭据(假设使用 OIDC 换取场景令牌)
buildkite-agent meta-data set "CI_BUILD_ID" "$BUILDKITE_BUILD_ID"
# 构建后对产物签名(示例用 cosign)
cosign sign --key cosign.key "registry.example.com/app:${BUILDKITE_BUILD_ID}"
# 下游校验
cosign verify --key cosign.pub "registry.example.com/app:${BUILDKITE_BUILD_ID}"
#
★★★

3. 如何用 grype 对容器镜像与 SBOM 进行漏洞扫描,并将扫描结果接入 CI 门禁与修复流程?

如何使用 grype 对容器镜像和 SBOM 进行漏洞扫描,并将扫描结果接入 CI 门禁与修复流程?

  • grype 扫描镜像与 SBOM 的用法
  • 扫描结果解析与门禁判断(阈值/失败策略)
  • 与修复流程的联动(生成修复建议、自动升级)

grype 是 Anchore 开源的漏洞扫描工具,可扫描容器镜像、文件系统与 SBOM(SPDX/CycloneDX)。常见用法是 grype <image> 扫描镜像,或 grype sbom:./sbom.json 扫描 SBOM,输出格式支持 JSON(-o json)、表格式等,便于后续解析。将其接入 CI 门禁时,通常用 grype <image> --fail-on high 这类参数让扫描在出现 Critical/High 漏洞时以非零退出码失败,从而阻断构建;或解析 JSON 输出,自行判断指定漏洞数量是否超过阈值。修复流程方面,grype 的 JSON 输出中包含每个漏洞对应的 fix 版本(fixes),可据此生成升级建议,配合 Renovate/Dependabot 或包管理器升级基础镜像与依赖,形成"扫描→评级→门禁→修复→复扫"闭环。

grype 的价值在于"扫描+门禁+修复"的一体化:它不仅能给出漏洞清单,还能通过 --fail-on 与退出码直接联动 CI 门禁,而 JSON 输出中的 fix 信息则为修复提供了可执行的数据。接入的重点是定义合适的分级阈值(避免一票否决过于激进),并对"已知风险但无修复"的例外进行管理。

# 扫描镜像并在任一 Critical/High 漏洞时失败(退出码非 0)
grype registry.example.com/app:latest --fail-on high
# 扫描 SBOM 并输出 JSON 供解析
grype sbom:./sbom.json -o json > scan.json
# 从 JSON 提取带修复版本的漏洞
jq -r '.matches[] | select(.vulnerability.fix.versions != null) | [.vulnerability.id, .vulnerability.fix.versions[0]] | @tsv' scan.json
#
★★

4. Bazel remote cache 在共享构建缓存时存在哪些供应链风险(如缓存投毒),如何缓解?

Bazel 的 remote cache 在共享构建缓存时存在哪些供应链风险(如缓存投毒),应如何缓解?

  • 共享构建缓存的价值与攻击面
  • 缓存投毒的攻击方式
  • 缓解措施(缓存隔离、认证、校验、不可信缓存策略)

Bazel remote cache 通过共享构建产物加速构建,但共享缓存也引入了供应链风险。最主要的风险是"缓存投毒"(cache poisoning):攻击者若能向缓存中写入伪造的构建产物,受害者后续构建命中该缓存时就会使用被篡改的产物(例如塞入恶意代码的二进制),从而在不触发构建的情况下被注入。缓解措施包括:对缓存服务启用认证与访问控制,只允许受信任的构建者写入;将缓存按"信任级别/项目/仓库"隔离,避免不同信任域共享同一缓存;对缓存内容做完整性校验(Bazel 本身基于内容寻址,缓存条目由 action 的 hash 定位,但需确认远端缓存未被恶意替换);对不可信缓存,可配置只命中、禁止其作为构建结果来源,或对关键产物做签名/校验;同时限制缓存中可执行产物的来源,避免从不可信缓存直接执行。

remote cache 的投毒风险源于"缓存命中会绕过本地构建"这一特性——一旦命中被投毒的缓存,受信任的构建流程也会执行恶意产物。因此核心思路是"信任域隔离"与"写权限控制":缓存可以被谁读、谁写,必须基于受信任的构建身份,并通过认证、隔离与校验把不可信内容挡在构建结果之外。

# 为 remote cache 配置带认证的 HTTP 缓存(示例)
bazel build //:target \
  --remote_cache=https://cache.example.com \
  --remote_timeout=60 \
  --remote_upload_local_results=true
# 仅允许本地或受信任构建者写入的策略,通过缓存服务端 ACL 控制
# 对关键产物做签名后在 CI 中校验
#
★★

5. Renovate 如何自动化依赖升级,其升级分组、频率控制与回归风险如何管理?

Renovate 如何实现依赖升级的自动化?升级分组、频率控制与回归风险分别如何管理?

  • Renovate 的升级 PR 生成机制
  • 升级分组(packageRules)与频率控制(schedule)
  • 回归风险控制(自动合并策略、测试门禁、rebase)

Renovate 是开源的依赖升级机器人,通过定时扫描仓库的依赖清单(如 package.json、requirements.txt、Dockerfile 等),发现新版本后自动创建升级 PR。升级分组用 packageRules 配置,可将同一类依赖合并到一个 PR(如所有 devDependencies 或某个互相关联的库),减少 PR 数量、便于集中测试;频率控制用 schedule 字段限制升级 PR 的创建时间(如仅在非工作时段),避免频繁打扰。回归风险控制方面,可以将升级 PR 与 CI 门禁联动(自动运行测试与构建),只有通过的 PR 才可合并;对低风险依赖可配置自动合并(automerge),对高风险/大版本升级则要求人工评审;升级 PR 会随源分支变化自动 rebase,保证测试的是最新代码。此外可通过 enabled 关闭某些依赖、ignoreDeps 跳过特定依赖,或用 separateMajorMinor 区分大版本与小版本升级。

Renovate 自动化的关键是"分组"与"节奏":分组决定升级 PR 的粒度(影响测试与评审成本),频率与自动合并决定升级的侵入性。回归风险的核心是让每个升级 PR 都经过 CI 测试门禁,并区分自动合并与人工评审的边界,从而在保持依赖最新的同时控制引入回归的风险。

// renovate.json 示例
{
  "packageRules": [
    { "matchUpdateTypes": ["patch", "minor"], "automerge": true },
    { "matchDepTypes": ["devDependencies"], "groupName": "devdeps" },
    { "matchPackageNames": ["react"], "major": { "enabled": true } }
  ],
  "schedule": ["after 10pm every weekday"],
  "separateMajorMinor": true
}
#
★★

6. Tekton Chains 如何在 CI 流水线中为构建产物生成签名与可验证的 provenance 溯源信息?

Tekton Chains 如何在 CI 流水线中为构建产物生成签名与可验证的 provenance 溯源信息?

  • Tekton Chains 在 Tekton 流水线中的角色
  • 签名与 provenance 的生成流程
  • 存储与验证(OCI 注解、attestation)

Tekton Chains 是 Tekton 上游用于供应链安全(SLSA)的组件,它能自动为 Tekton PipelineRun 产生的构建产物生成签名与 provenance(出处/溯源)信息,并保存为可验证的 attestation(证明)。其工作流程是:在 Tekton 流水线提交到集群后,Chains 控制器监听 PipelineRun/TaskRun 完成事件,调用配置的签名器(如 cosign、kms)对产物镜像或 SBOM 签名,并生成 SLSA provenance(描述构建过程、输入输出、命令等),再通过 storage 后端(如 OCI registry、对象存储)把签名与 attestation 保存下来,通常以 in-toto attestation 格式写入。下游可通过 cosign verify-attestation 验签并核验 provenance,从而建立"产物由谁、何时、如何构建"的可信记录。其配置通过 chains-config ConfigMap 与 signing-secrets 管理密钥。

Chains 的价值在于把"签名与 provenance"从人工步骤变成流水线的自动产物:它不依赖构建代码本身,而是通过控制器在流水线生命周期内自动为产物生成 SLSA 证据,且与 cosign/in-toto 生态兼容,便于纳入 SLSA 验证。这使 CI 构建结果不仅能被信任,还能被验证其来源与构建过程。

# 查看 Chains 配置(签名器与存储后端)
kubectl get configmap chains-config -n tekton-chains -o yaml
# 校验产物镜像的 attestation
cosign verify-attestation --key cosign.pub \
  --type slsaprovenance registry.example.com/app:latest
#
★★

7. cosign verify 如何校验镜像签名与完整性,签名密钥管理与验证失败如何处理?

cosign verify 如何校验镜像的签名与完整性?签名密钥如何管理,验证失败时应如何处理?

  • cosign verify 的验证流程与验证对象
  • 签名密钥管理(密钥轮换、KMS、公共密钥的分发)
  • 验证失败的处理与降级策略

cosign verify 会从镜像仓库中读取镜像的签名(signature)与预留的完整性信息,用对应的公钥对签名进行验签,并校验镜像内容与签名时的一致性(cosign 签名基于镜像 digest,可防止镜像被替换后签名仍有效)。验证时通过 --key 指定公钥,或通过 --certificate-identity/--certificate-oidc-issuer 校验由证书或 OIDC 身份签名的镜像。签名密钥管理方面,密钥应使用硬件/KMS 保护(如 cosign generate-key-pair --kms),私钥绝不出现在构建机或 CI 日志中,并定期轮换;公钥需通过可信渠道分发(如分开的仓库、KMS、公开 key 文件),并在验证时指定正确的公钥。当验证失败时,应区分原因:签名缺失、密钥不匹配、镜像被篡改、或证书过期。对于签名缺失的镜像,应阻断其部署(fail-closed),而非静默放行;对密钥不匹配或镜像被篡改,则应告警并隔离该镜像,追溯其来源。

cosign 验证的核心是"把信任绑定到签名与密钥":只有持有正确公钥的一方才能验证镜像是否由受信任者签名且未被篡改。因此密钥管理(私钥安全、公钥可信分发)与验证失败策略(fail-closed)同样重要——验证失败本该是最重要的告警信号,绝不能因为"流程麻烦"而允许跳过验签。

# 用公钥校验镜像签名与完整性
cosign verify --key cosign.pub registry.example.com/app:latest
# 校验由 OIDC 身份签名的镜像
cosign verify --certificate-identity ci@example.com --certificate-oidc-issuer https://provider.example.com registry.example.com/app:latest
# 生成 KMS 保护的密钥对
cosign generate-key-pair --kms awskms:///arn:aws:kms:...
#
★★

8. package-lock.json 在依赖锁定中的作用与失效场景,即锁定后为何仍可能引入漏洞或被替换?

package-lock.json 在依赖锁定中起什么作用?锁定后为何仍可能引入漏洞或被替换?

  • 锁文件锁定依赖树与完整性的机制
  • 锁文件失效/过时的场景(手动修改、registry 变更、版本漂移)
  • 供应链风险(lockfile 被替换、依赖被投毒)

package-lock.json 记录了完整的依赖树(直接与传递依赖)的精确版本、resolved 地址与 integrity 校验值,default install 时按锁文件安装,从而保证可复现。但它并非绝对安全:一方面,锁文件可能"过时"——如果开发者手动修改 package.json 后未同步更新锁文件、或用 --no-package-lock/--force 安装、或锁文件未提交同步,就可能产生锁文件与实际依赖不一致;另一方面,攻击者可能直接替换/投毒 lockfile(例如通过恶意 PR 或偷取仓库写权限),使其中包含指向恶意 registry 或恶意包的 resolved 地址与哈希。此外,即使锁文件正确,若其指向的 registry 或包源被投毒(哈希被重新计算),或基础依赖在一段时间后公开了新漏洞,那么"锁定"的版本本身就含漏洞,锁文件并不能保证"无漏洞",只能保证"可复现"。

锁文件的作用是"可复现与完整性",而非"安全无漏洞"。它的失效场景分为两类:流程失效(锁文件与实际依赖漂移、被覆盖)与供应链失效(lockfile 被替换、依赖源被投毒、锁定版本本身含漏洞)。因此锁文件需要配合"锁定后的校验"(如 frozen-lockfile)、"来源校验"(integrity)与"漏洞扫描"(对锁定版本做扫描)才能发挥防护作用。

# 以冻结锁文件方式安装,避免锁文件与依赖漂移
npm ci
# 校验依赖树是否与锁文件一致
npm install --package-lock-only
# 对比锁文件完整性
npm ci --dry-run
#
★★

9. 供应链攻击的类型与防护中依赖投毒、构建劫持、分发篡改与凭据窃取各自的防护重点

供应链攻击的主要类型有哪些?依赖投毒、构建劫持、分发篡改与凭据窃取各自的防护重点是什么?

  • 供应链攻击的四种主要类型
  • 各类型攻击的机理与防护重点
  • 端到端防护体系

供应链攻击主要分为四类:依赖投毒(dependency confusion / typosquatting / 恶意包上传),攻击者通过伪造或恶意包诱导开发者安装,防护重点是依赖源校验、锁定版本、SBOM 与漏洞扫描、对包名与来源的审查;构建劫持(build hijacking),攻击者注入恶意构建代码或篡改 CI 配置,使构建产物被污染,防护重点是构建环境隔离、CI 配置完整性、产物签名与 provenance;分发篡改(distribution tampering),攻击者在产物分发环节篡改镜像/二进制,防护重点是签名校验、镜像 digest 固定、HTTPS 与 integrity 校验;凭据窃取(credential theft),攻击者窃取 CI 密钥或开发者凭据获得写入权限,防护重点是最小权限、短期令牌、密钥轮换与审计。这些防护共同构成"开发-构建-分发-消费"全链路的信任体系。

四类攻击分别命中供应链的不同环节:依赖投毒发生在"依赖获取",构建劫持发生在"构建过程",分发篡改发生在"产物分发",凭据窃取则是支撑前几类的"前置能力获得"。因此防护要覆盖全链路,且最关键的是"签名与验证"(让产物可验证)与"最小权限/隔离"(降低被劫持与窃取的影响面)。

#
★★

10. 如何构建 hardened runner,即最小化运行环境、隔离执行与 CI 凭据保护?

如何构建 hardened runner?包括最小化运行环境、隔离执行与 CI 凭据保护三个方面?

  • 最小化运行环境(精简镜像、去不必要的工具)
  • 隔离执行(运行环境隔离、网络限制、不可信代码隔离)
  • CI 凭据保护(最小权限、短期令牌、注入方式)

构建 hardened runner 从三个层面入手:最小化运行环境——使用精简、锁定版本的基础镜像(如 distroless、Wolfi),移除不必要的工具(如去除 shell、包管理器、调试工具),只保留构建所需的依赖,减少攻击面;隔离执行——将 runner 运行在隔离环境(容器、VM、受控沙箱)中,限制其网络访问(如仅允许访问所需 registry),对不可信代码(如第三方 PR)使用更低权限的隔离执行,避免 host 与构建环境被污染;CI 凭据保护——凭据通过 secret 管理注入,遵循最小权限(只授予构建需要的权限),优先使用短期令牌与 OIDC 动态凭据,避免长期密钥,并确保凭据不进入日志、不落入构建产物。通过 self-hosted runner 也需定期更新与加固 agent 本身。

hardened runner 的核心思想是"最小暴露 + 隔离 + 最小权限":最小化环境让攻击面最小,隔离执行让一个构建的注入不影响其他构建或 host,凭据保护让被攻破的 runner 无法窃取持久权限。三者共同保证"即使构建环境被攻破,影响也有限且可追溯"。

# 用精简镜像运行 runner(示例 Dockerfile 片段)
FROM cgr.dev/chainguard/wolfi-base:latest
# 限制 runner 的网络访问(示例:仅允许推送到目标 registry)
# 通过 OIDC 换取短期凭据,而非长期密钥
#
★★

11. 自建镜像仓库/registry mirror 在供应链安全中的作用,即版本缓存、上游校验与访问控制?

自建镜像仓库或 registry mirror 在供应链安全中起什么作用?版本缓存、上游校验与访问控制分别如何设计?

  • registry mirror 的版本缓存与拉取加速
  • 上游校验(镜像来源、digest、签名)
  • 访问控制(认证、授权、镜像隔离)

自建镜像仓库/registry mirror 在供应链安全中的作用是:通过版本缓存(caching)将上游镜像缓存到本地,既加速拉取、减少对上游的依赖,也提供一个可控的镜像分发点;同时作为"信任边界",对上游镜像做校验——只允许经过验证的镜像进入本地仓库(如校验 digest、签名、扫描无高危漏洞),阻断来自不受信源的镜像;并提供访问控制(RBAC、认证、镜像命名空间隔离),确保只有受信任的构建与部署环境能拉取或推送镜像,防止未授权镜像被使用或篡改。镜像的不可变性(immutable tags/digest)也在此得到强化,防止 tag 被覆盖指向被篡改的镜像。

registry mirror 的价值是"把外部的不可信源聚合成一个受控的信任边界":缓存解决可用性与性能,校验解决"源头可信",访问控制解决"谁可以用"。这样即使上游发生投毒,也能在镜像进入本地分发体系前被拦截,且可追溯镜像的来源与版本。

# 配置 containerd 使用本地 mirror(示例)
# /etc/containerd/certs.d/registry.example.com/hosts.toml
server = "https://registry.example.com"
[host."https://proxy.example.com"]
  capabilities = ["pull", "resolve"]
#

12. GitHub Dependabot 如何自动发现依赖漏洞并生成升级 PR,其安全更新机制与配置要点是什么?

GitHub Dependabot 如何自动发现依赖漏洞并生成升级 PR?其安全更新机制与配置要点是什么?

  • Dependabot 的漏洞发现与 PR 生成机制
  • 安全更新(security updates)与版本更新(version updates)的区别
  • 配置要点(自动合并、分批、schedule)

GitHub Dependabot 通过持续监测依赖源(如 GitHub Advisory Database)与仓库的依赖清单,发现依赖存在已知漏洞时,自动生成升级 PR,将依赖更新到修复版本;它还支持"版本更新"(version updates),定期将依赖升级到较新版本。安全更新(security updates)专门针对漏洞修复,会尽快生成补丁 PR;版本更新则按配置的 schedule 运行。配置要点包括:启用 Dependabot 的自动合并(需要配合 CI 门禁)、按依赖分组(grouped updates)减少 PR 数量、设置更新频率(daily/weekly/monthly)、用 open-pull-requests-limit 控制并发 PR 数、为安全更新设置更紧凑的节奏,并将 PR 与 CI 测试联动,确保升级无回归。Dependabot 配置在 .github/dependabot.yml 中。

Dependabot 的价值在于"自动发现+自动生成升级 PR",把漏洞修复从"人工发现"变成"自动化驱动"。安全更新与版本更新的区别在于优先级:安全更新以修复漏洞为直接目标、节奏更快,版本更新是常规维护。配置的要点是让自动 PR 与 CI 门禁、评审流程配合,平衡更新速度与回归风险。

# .github/dependabot.yml 示例
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule: { interval: "weekly" }
    groups:
      dev-deps: { patterns: ["*"], dependency-type: "development" }
    open-pull-requests-limit: 10
#

13. GitLab Dependency Scanning 如何对依赖进行漏洞扫描,结果如何与 MR 门禁和修复流程联动?

GitLab Dependency Scanning 如何对依赖进行漏洞扫描?扫描结果如何与 MR(合并请求)门禁和修复流程联动?

  • GitLab Dependency Scanning 的扫描机制
  • 扫描结果与 MR 门禁的联动(merge request compliance)
  • 与修复流程的联动(创建 issue、Dependabot 类更新)

GitLab Dependency Scanning 是 GitLab 内置的依赖漏洞扫描能力,在 CI 流水线中通过 gemnasium 等扫描器对项目依赖(如 Go、npm、Python、container 等)进行扫描,基于漏洞数据库(如 GitLab Advisory Database)检测已知漏洞,并生成漏洞报告(JSON 报告)。其结果可通过 GitLab 的 merge request 门禁联动:在 MR 中启用"merge request approval"或"compliance"规则,当扫描发现指定严重度(如 Critical/High)漏洞时自动阻止 MR 合并;同时结果会写入项目的安全仪表盘,便于跟踪。修复流程方面,可为发现的漏洞自动创建 issue,或通过 GitLab 的自动依赖更新(Dependabot 类功能,如 renovate 集成)生成升级 MR,将漏洞修复带入流水线,形成"扫描→门禁→修复→复扫"闭环。

GitLab Dependency Scanning 的工程价值在于把扫描结果"原生"嵌入 GitLab 的 MR 工作流:门禁让漏洞成为合并的前置条件,避免带漏洞的代码合入;修复流程则通过 issue 与自动更新 MR 把发现转化为行动。与云原生工具链的扩展(如接入 SBOM)也使其在供应链治理中更完整。

# .gitlab-ci.yml 启用 Dependency Scanning
include:
  - template: Jobs/Dependency-Scanning.gitlab-ci.yml
dependency_scanning:
  stage: test
  artifacts:
    reports:
      dependency_scanning: gl-dependency-scanning-report.json
#

14. SLSA 等供应链安全框架如何指导落地,各级别(L1-L4)分别要求哪些实践?

SLSA 等供应链安全框架如何指导供应链安全落地?各级别(L1-L4)分别要求哪些实践?

  • SLSA 框架的定位与目标
  • L1-L4 各级别的核心要求
  • 落地路径与优先级

SLSA(Supply chain Levels for Software Artifacts)是一个供应链安全框架,通过定义从 L1 到 L4 的递进级别,指导软件产物如何被可信地构建、签名与溯源。L1 要求"构建脚本已文档化"(build script),即构建过程可复现、可记录;L2 要求"构建由受托管服务执行,并生成签名 provenance"——构建必须在受控的托管 CI 上运行,并生成带签名的构建出处(provenance);L3 要求"构建由独立于源仓库的受控服务执行,防止源仓库控制构建"——也就是构建者与源仓库隔离,防止源代码被篡改后影响构建;L4 是最高级别,要求"构建系统在整个构建生命周期内可被证明完全受控,且安全加固",包括对构建机、权限、密钥的强验证。落地上通常从 L1/L2 起步(先有可复现构建与签名 provenance),再逐步提升到 L3/L4 的构建隔离与强验证。

SLSA 的价值在于把抽象的安全目标拆解为可操作的级别,让团队按级别逐级提升。核心逻辑是"信任"的迁移:L1 保证可复现,L2 保证托管+签名,L3 保证构建者与源隔离,L4 保证构建系统本身受控。落地时按 L1→L4 渐进,优先做"签名 provenance + 托管构建"这两项性价比最高的实践。

# 生成 SLSA provenance(以 cosign 生成 in-toto provenance 为例)
cosign attest --type slsaprovenance --predicate provenance.json registry.example.com/app:latest
#

15. 发现依赖投毒或仓库劫持事件后的应急响应,包括影响面评估、阻断、溯源与加固?

发现依赖投毒或仓库劫持事件后应如何应急响应?包括影响面评估、阻断、溯源与加固?

  • 影响面评估(受影响包、依赖链、环境)
  • 阻断(禁用包、隔离受影响环境)
  • 溯源(定位攻击途径、时间线)与加固(长期防护)

依赖投毒或仓库劫持事件的应急响应(IR)流程包括:首先进行影响面评估——确定被投毒的包名、版本、受影响的下游依赖与部署环境,通过 SBOM 和依赖树反查哪些服务/产物使用了该包,评估其暴露范围与数据风险。其次阻断——立即将受影响的包从依赖清单中移除或锁定到安全版本,禁用恶意版本,暂停相关镜像/产物的部署,隔离受影响环境以防横向扩散。然后溯源——分析投毒入口(伪造包名、typosquatting、被劫持的账户/仓库、CI 密钥泄露),结合日志与时间线确定攻击途径与最早入侵时间,评估泄露范围。最后加固——加强依赖锁定与校验(锁文件、integrity、签名)、启用来源校验与扫描、收紧 CI 凭据与仓库权限、实施 SBOM 与监控,防止同类事件再次发生。

供应链事件 IR 的关键是"先止血再溯源":影响面评估决定阻断范围,阻断要快(宁可过度阻断),溯源用于根因与范围确定,加固则把一次性事件转化为长期防护。由于依赖投毒往往影响面广而隐蔽,SBOM 与依赖树是快速反查影响面的关键工具。

# 用 SBOM 反查受影响服务
grep -r "malicious-package" sbom*.json
# 锁定依赖并重新安装
npm update <pkg> --save
# 清理被投毒包并校验
npm ci --force
#

16. 如何建立供应链漏洞情报监控与告警,即情报源选择、扫描频率与告警降噪?

如何建立供应链漏洞情报监控与告警?包括情报源选择、扫描频率与告警降噪?

  • 漏洞情报源的选择(NVD、GitHub Advisory、商业情报)
  • 扫描频率与触发时机
  • 告警降噪(去重、分级、关联资产)

建立供应链漏洞情报监控与告警,首先选择情报源:常用 NVD(美国国家漏洞库)、GitHub Advisory Database、OSV、GitLab Advisory 以及商业情报源(如 Snyk、Qualys、VulnDB),不同源覆盖范围与时效不同,可组合使用以互补。其次确定扫描频率与触发时机:对持续交付的镜像/依赖可做"每次构建即扫"(CI 门禁),对存量资产做周期性扫描(如每日/每周),并对新披露的高危漏洞(如 CISA KEV、Log4Shell 类事件)触发即时专项扫描。再次是告警降噪:将多源漏洞去重(按 CVE 聚合)、结合资产的暴露面与利用情况(如 EPSS 概率、KEV 已知被利用)分级,只对"有实际影响"的告警通知,并关联到具体资产与负责人,避免海量告警淹没关键信息。

情报监控的核心是"源的选择 + 节奏 + 降噪":单一情报源有盲区,需组合;扫描频率要兼顾时效与成本(构建时扫 + 周期扫 + 事件触发扫);降噪则决定告警是否可执行——只告警"有影响且可行动"的漏洞,而非所有漏洞。EPSS/KEV 与资产关联是降噪的关键手段。

#

17. 如何生成与维护 SBOM(如 SPDX/CycloneDX 格式),并在漏洞排查与合规审计中使用?

如何生成与维护 SBOM(如 SPDX/CycloneDX 格式)?如何在漏洞排查与合规审计中使用?

  • SBOM 的生成工具与格式(SPDX/CycloneDX)
  • SBOM 的维护(版本化、随产物发布)
  • 在漏洞排查与合规审计中的应用

SBOM(软件物料清单)列出软件的所有组件及其版本、供应商与依赖关系,常用格式为 SPDX 与 CycloneDX。生成工具包括 syft(扫描镜像/目录生成 SBOM)、cyclonedx-bombom 等,输出为 JSON/XML 的 SPDX 或 CycloneDX 格式。维护时,SBOM 应随每个构建产物一起生成并版本化、随镜像/产物发布(如作为 OCI 注解或单独文件),保持与产物一致。在漏洞排查中,可用 SBOM 快速反查受影响组件(结合漏洞库匹配 CVE 与版本),属影响面评估的高效手段;在合规审计中,SBOM 可作为软件成分披露、许可合规(License compliance)与供应链证明(如 SLSA 的一部分)的依据,向监管或客户证明软件组成透明、可追溯。

SBOM 的价值在于"把软件的组成变成可查询、可审计的结构化数据":它既是漏洞排查的影响面反查工具,也是合规审计的披露依据。核心是"随产物生成、版本化、可追溯",否则 SBOM 与产物脱节就失去意义。生成后与漏洞库匹配即可将"扫描"扩展为"全量反查"。

# 用 syft 生成 CycloneDX SBOM
syft registry.example.com/app:latest -o cyclonedx-json > sbom.json
# 用 grype 结合 SBOM 做漏洞反查
grype sbom:./sbom.json -o json > scan.json
#

18. 软件供应链安全的主要防线有哪些(签名验证、漏洞扫描、依赖锁定),各自防护重点是什么?

软件供应链安全的主要防线有哪些(签名验证、漏洞扫描、依赖锁定)?各自防护重点是什么?

  • 签名验证(信任与完整性)
  • 漏洞扫描(已知漏洞发现)
  • 依赖锁定(可复现与来源固定)

软件供应链安全的主要防线有三道:签名验证、漏洞扫描与依赖锁定。签名验证(如 cosign、GPG)的防护重点是"信任与完整性"——确保产物(镜像、二进制)确实由受信任者构建且未被篡改,通过公钥验签与 digest 校验实现;漏洞扫描(如 grype、Trivy)的防护重点是"已知漏洞发现"——检测依赖与镜像中已公开的 CVE,并给出修复建议,侧重"已知问题"的排查;依赖锁定(如 lockfile、固定版本)的防护重点是"可复现与来源固定"——保证依赖树可复现、来源固定,防止版本漂移与来源被替换。三者的协同:依赖锁定保证"装的是什么",漏洞扫描保证"装的版本有没有已知漏洞",签名验证保证"产物是否可信且未被篡改",共同构成"来源可信 + 内容可复现 + 漏洞已知"的完整防线。

三道防线各有侧重又互补:锁定解决"可复现/来源",扫描解决"已知漏洞",签名解决"信任/完整性"。单独使用任何一道都有盲区——锁定不能防漏洞,扫描不能防篡改,签名不能防已含漏洞的版本。因此供应链安全需要三者叠加,并配合 SBOM 与 provenance 形成完整体系。