CIS 软件供应链安全指南

概述

Argon(现在是 Aqua Security 的一部分)曾经联系 CIS(Center for Internete Security),建议为软件供应链安全开发一种 CIS 基线。多年以来,CIS 开发并发布了很多安全配置指南,但是软件供应链安全方面还是一个空白。现代软件开发过程中会涉及大量的平台和技术,软件供应链安全的工作范围应该有多大?如何保证基线能够在多种平台中保持一致?

很明显,要直接定义特定的基线是不现实的,更实际的做法是定义一个通用的指南,然后以此为基础来进一步定义更精准的内容。因此 CIS 软件供应链安全指南诞生了。这篇指南的目的在于引出全球社区的反馈,从而帮助制定未来的更准确、更针对特定平台的指南。

01

本指南面向下图所示的软件供应链过程,涵盖了从代码到交付的生命周期。

02

本指南目前包含了一百多条建议,按照以下维度进行组织:

  1. 源码:关于正确管理源码的的安全建议

    这是软件供应链的第一环节,源码是这一过程的真相之源,因此供应链安全的管理要从源码开始,管理内容包括脆弱性、错误配置以及敏感数据等。

  2. 构建管线:对构建组件的管理和安全建议。

    构建组件包含了构建管线——获取原始代码文件、运行一组任务,最后输出物料。这部分包含构建管线的环境、管理和运行方面的建议。这是软件供应链的第二个环节,针对这一环节的攻击(例如 Codecov 或 SlolarWinds)越来越频繁。

  3. 依赖:构建和发布过程中会引入多种依赖内容,这些内容会变成软件的一部分。本节建议针对依赖内容提出。

    依赖可能进入代码,还可能被构建管线使用,因此是软件供应链中的一个主要组成部分。被依赖内容经常是由第三方开发者提供的,可能受到特定攻击(例如 log4j)。

  4. 制品:对构建管道产生的制品,以及应用程序在构建过程中使用的制品进行管理的安全建议。

    制品是软件的打包版本。可以用软件包仓库(或工件管理器)保存制品。制品的创建、复制、直至被部署到相关的环境中,都需要具备保障能力。

  5. 部署:针对应用部署过程、配置和相关文件的安全建议。

    软件供应链的最后一环。在这之后,应用将在生产环境中运行,供给客户使用。如何将物料安全地交付给客户,至关重要。

本指南和 CIS 基准的愿景,是支持关键的新兴标准,如软件产品的供应链级别(SLSA)和更新框架(TUF),为基准支持的平台上的配置设置和审计工作奠定基础。

通过制定 CIS 软件供应链指南,CIS 和 Aqua 希望建设一个活跃的社区,来支持开发未来的针对平台的软件供应链基线。呼吁开发这些平台或与这些平台合作的专家(Subject Matter Experts)以 CIS 的协作和共识方式帮助创建这一指南。

迄今为止,来自 Aqua Security、CIS、Microsoft、PayPal、Red Hat、CyberArk、Axonius 等组织的 SME 们已经对本指南进行了评审。CIS 和 Aqua Security 希望开放目前工作成果的方式,吸引有更多的 SME 为这个项目做出贡献,使所有人受益。

要贡献给 CIS 基线项目,请联系 CIS 基线开发团队:benchmarkinfo@cisecurity.org。

预期读者

本指南适用于计划通过 DevOps 管道的自动化手段构建和部署软件更新的开发、部署、评估或保护解决方案的 DevOps 和应用安全管理员、安全专家、审计师、Help Desk 和平台部署人员。

1. 源码

1.1 代码变更

1.1.1 使用版本控制平台来跟踪代码变更

1.1.2 确保能够从变更代码回溯到对应的任务

1.1.3 保证由两个强认证用户对代码变更进行评审和放行

1.1.4 如果代码变更的内容发生了更新,那么之前批准的变更申请应该作废

1.1.5 对于撤销变更评审结果的权限应该严加管控

1.1.6 为敏感代码或配置设置明确的所有者

1.1.7 代码属主的代码发生变更时,必须由属主进行审批

1.1.8 周期性地对不活跃分支进行评审和删除

1.1.9 合并新代码之前,必须通过所有检查

1.1.10 进行代码合并之前,确保 Git 分支是最新的

1.1.11 进行代码合并之前,确保所有开放注解都已经解决

1.1.12 合并之前需要对提交内容进行签署

1.1.13 留存 Linear History(仅能合并 Squash 或 Rebase 内容)

1.1.14 制定分支的管理规则

1.1.15 确保由特定的个人或者团队来完成代码合并过程

1.1.16 拒绝向保护分支强行推送代码

1.1.17 只有推送权限的用户不能删除分支

1.1.18 所有的合并操作都需要进行风险扫描

1.1.19 分支保护规则的变更需要进行审计

1.2 仓库管理

1.2.1 所有公开仓库都应该包含 SECURITY.md 文件

1.2.2 只有特定人/角色能够创建仓库

1.2.3 只有特定人/角色能够删除仓库

1.2.4 只有特定人/角色能够删除 Issue

1.2.5 确保跟踪所有代码的副本(分叉)

1.2.6 确保跟踪项目代码的可见性(可访问性)变化

1.2.7 周期性的评审不活跃代码仓并进行归档

1.3 访问代码库

这一节包含了在管理应用代码访问过程中的推荐安全措施。这其中包含了对内部和外部访问、账号管理、授权、认证方式等方面的内容。对于访问的安全限制是阻止攻击的重要手段,因此这一节内容是软件安全的重要组成部分。

本节对管理员账户和普通账户分而治之。因为管理员的权限过大,因此管理员账户只应用于管理工作,而非日常任务。

1.3.1 周期性评审不活跃用户并进行删除

1.3.2 确保只有特定用户才能创建团队

1.3.3 严格限制管理员数量

1.3.4 组织外贡献者需要进行多因素认证

1.3.5 组织成员需要进行多因素认证

1.3.6 组织中的现有用户可以邀请新用户加入,新成员只能使用公司认证的邮箱接收邀请

1.3.7 每个代码仓都需要有两个管理员

1.3.8 为代码仓设置严格的基础(缺省)权限

1.3.9 明确标识认证的组织,防止被仿冒

1.3.10 确保仅向认证的域发送源码管理系统的通知邮件

1.3.11 组织应提供 SSH 认证方法

1.3.12 根据 IP 地址限制 Git 访问

1.3.13 跟踪反常的代码访问行为

1.4.1 安装自动化插件/工具需要由管理员批准

1.4.2 周期性地检查过期插件/工具,并删除

1.4.3 应限制自动化工具/插件的最小权限

1.5 代码风险

本节包含代码安全扫描方面的建议。例如硬编码的敏感信息、常见的导致易受攻击的配置错误或者严格的授权等。因为应用代码有很多组件,因此需要逐一检查。

1.5.1 确保使用扫描器鉴别并阻止代码中出现敏感数据

1.5.2 CI 管线中应该有扫描器

1.5.3 IaC 指令必须通过扫描器的检查

1.5.4 用扫描器扫描漏洞

1.5.5 确保使用扫描器扫描引用的开源包中的漏洞

1.5.6 确保使用扫描器扫描引用的开源包的授权

2. 构建管线

本节针对组织开发的构建管线,提出安全建议。

构建管线是一组基础设施,会读取原始的代码问价,运行一组任务,最终输出制品。制品是软件最近版本的最终输出物,这些输出物会被打包以便于后续的存储、使用和部署。

2.1 构建环境

本节针对构建管线的环境提出安全建议。构建环境包含所有制品构建过程所需的基础设施——编排器、管线执行、构建器所在的环境等。绝大多数构建环境的安全建议是针对自建构建平台的——例如自建的 Circle CI。

2.1.1 每个管线都有单一职责,确保最小化权限

2.1.2 每个管线的基础设施和配置都是不可变的

2.1.3 需要保存构建环境的日志

2.1.4 能够自动创建构建环境

2.1.5 对构建环境进行访问控制

2.1.6 仅有认证用户能够访问构建环境

2.2 构建 Worker/Runner

2.2.1 每种构建 Worker 只有单一用途

2.2.2 构建 Worker 的运行环境和命令应该是从外部推送给 Worker,而不是由 Worker 主动拉取

2.2.3 不同 Worker 的职责应该分离

2.2.4 尽可能缩减 Worker 的网络连接能力

2.2.5 Worker 需要进行加固保障运行时安全

2.2.6 要对 Worker 进行漏洞扫描

2.2.7 Worker 的部署配置应该保存在版本控制系统里

2.2.8 监控 Worker 的资源消耗

2.3 管线指令

管线中使用指令来获取源代码的原始文件,并进行一系列处理最终输出制品。多数时候,这些指令是由第三方开发者编写的,受攻击的几率可能较高,因此需要谨慎对待。

2.3.1 确保所有构建步骤都以代码定义

将管道指令作为代码存储在版本控制系统中,提高了构建步骤的自动化程度,并减少人为错误导致的安全漏洞。此外,这种做法也具备了恢复管道配置版本的能力,在发生恶意事件时,更容易准确的定位受影响的变化。

2.3.2 清晰声明构建步骤的输入和输出内容

2.3.3 确保输出内容写入到独立的、安全的存储仓

2.3.4 管线文件需要进行跟踪和评审

2.3.5 确保构建过程的触发有严格权限控制

2.3.6 使用自动扫描的方式保障管线配置正确性

2.3.7 使用自动扫描的方式避免管线漏洞

2.3.8 使用自动扫描的方式避免管线中出现敏感数据

2.4 管线完整性

确保管线、管线的依赖项以及相关制品都是真实的。管道的完整性能保障管道运行过程中的每一个变化和进程都是有保障的。一个办法就是将每个依赖关系锁定在某个安全版本上。

2.4.1 为所有版本的所有制品进行签名

2.4.2 锁定所有构建过程中的外部依赖

2.4.3 在引入依赖之前要进行验证

2.4.4 构建管线的制品生成应该具有复现能力

2.4.5 管线步骤应该能生成 SBOM(软件物料单)

2.4.6 管线应对生成的 SBOM 进行签名

3. 依赖

3.1 三方包

3.1.1 要对第三方制品和开源库进行校验

3.1.2 所有第三方供应商都应该提供 SBOM

3.1.3 构建过程生成的(历史)元数据应该被签名和校验

3.1.4 确保开源组件的依赖关系也得到监控

3.1.5 定义并优先使用受信任的包管理器及其包仓库

3.1.6 为代码的 SBOM 进行签名(*太啰嗦了*)

3.1.7 依赖应该锁定到一个特定的、验证过的版本

3.1.8 使用的所有包都发布于至少 60 天以前

3.2 包校验

3.2.1 要在组织范围内实施依赖使用策略

3.2.2 要能够自动扫描已知漏洞

3.2.3 要能够自动扫描许可问题

3.2.4 能够自动扫描包的属主变化

4 制品

制品是软件的打包成果,保存在包仓库中或者制品库中,从产生到拷贝、更新以及部署的整个过程都需要关注安全问题。

4.1 校验

制品被推送到仓库之后,可能发生各种攻击:例如使用同名恶意制品进行覆盖、盗取制品文件等。

4.1.1 所有制品都需要通过构建管线进行签名

4.1.2 分发之前对制品进行加密

4.1.3 只有认证平台才能对制品进行解密

4.2 访问制品

4.2.1 对制品进行认证,并且限制特定平台对特定的制品进行认证

4.2.2 尽可能少地授权用户上传制品

4.2.3 能够上传制品的用户需要使用 MFA 认证

4.2.4 制品库不应该使用本地的用户管理

4.2.5 禁止匿名访问制品库

4.3 包仓库

4.3.1 包仓库要对制品签名进行验证

4.3.2 所有制品的所有版本的签名都需进行验证

4.3.3 包仓库的配置变更需要进行审计

4.3.4 包仓库使用的 Webhook 需要用加密协议进行通信

4.4 可追溯

4.4.1 制品需要通过 SBOM、元数据文件等方式提供源头信息

4.4.2 禁止从外部仓库拉取私有制品

5. 部署

部署是供应链的最后一段,本节提供关于发布、部署和配置等方面的安全建议。

5.1 部署配置

5.1.1 确保部署配置文件和源码进行分离

5.1.2 部署配置的变更必须进行跟踪

5.1.3 用扫描器保障识别和阻止配置文件中出现敏感数据

5.1.4 只有特定用户才能访问部署配置

5.1.5 对 IaC 指令进行扫描,防止指令错误

5.1.6 确保对部署配置进行校验

5.1.7 部署配置应该绑定到特定的可信的版本

5.2 部署环境

5.2.1 用自动化的方式进行部署

5.2.2 可复制的部署环境

5.2.3 对部署环境进行访问限制

5.2.4 禁止使用缺省密码

Avatar
崔秀龙

简单,是大师的责任;我们凡夫俗子,能做到清楚就很不容易了。

comments powered by Disqus
下一页
上一页