依赖扫描

依赖扫描功能可以在您开发和测试应用程序时,自动查找软件依赖项中的安全漏洞。例如,依赖项扫描可以让您知道您的应用程序是否使用已知易受攻击的外部(开源)库。然后,您可以采取措施保护您的应用程序。

依赖扫描通常被认为是软件组合分析 (SCA) 的一部分。SCA 可以包含检查代码使用的项目的各个方面,这些项目通常包括几乎总是从外部源导入的应用程序和系统依赖项,而不是来自您自己编写的项目。

依赖项扫描可以在你应用程序生命周期的开发阶段运行。每次流水线运行时候,都会比较源分支和目标分支病识别漏洞。漏洞和其严重程度都会列在合并请求中,这能够让你在将代码变更提交之前正确识别你应用程序中的风险。还可以通过持续漏洞扫描来识别漏洞。

极狐GitLab 同时提供依赖项扫描和容器扫描来确保能够覆盖所有的依赖类型。为了尽可能覆盖更多的风险区域,我们鼓励你使用我们所有的安全扫描器。对于这些功能的对比,可以查看依赖项和容器扫描对比

Dependency scanning Widget

支持的语言和包管理器

依赖扫描自动检测仓库中使用的语言,运行与检测到的语言匹配的所有分析器,通常不需要自定义分析器的选择。我们建议不要指定分析器,以便您自动使用完整选择从而获得最佳覆盖范围,避免在出现弃用或删除时进行调整。 但是,您可以使用变量 DS_EXCLUDED_ANALYZERS 覆盖选择。

语言检测依赖于 CI 作业 rules,并从仓库的根目录中搜索最多两个目录级别。例如,如果仓库包含Gemfileapi/Gemfileapi/client/Gemfile,则启用 gemnasium-dependency_scanning 作业,但如果唯一支持的依赖文件是 api/v1/client/Gemfile,则不会启用。

对于 Java 和 Python,当检测到支持的依赖文件时,依赖扫描会尝试构建项目并执行一些 Java 或 Python 命令以获取依赖项列表。对于所有其他项目,无需先构建项目,即可解析锁定文件以获取依赖项列表。

当检测到支持的依赖文件时,将分析所有依赖项,包括传递依赖项。分析的嵌套或传递依赖项的深度没有限制。

支持以下语言和依赖项管理器:

语言 语言版本 软件包管理器 支持的文件 处理多个文件?
.NET 所有版本 NuGet packages.lock.json Y
C#
C 所有版本 Conan conan.lock Y
C++
Go 所有版本 Go
  • go.mod
Y
Java and Kotlin 8 LTS, 11 LTS, 17 LTS, or 21 LTS1 Gradle2
  • build.gradle
  • build.gradle.kts
N
Maven6 pom.xml N
JavaScript and TypeScript 所有版本 npm
  • package-lock.json
  • npm-shrinkwrap.json
Y
yarn yarn.lock Y
pnpm3 pnpm-lock.yaml Y
PHP All versions Composer composer.lock Y
Python 3.117 setuptools8 setup.py N
pip
  • requirements.txt
  • requirements.pip
  • requires.txt
N
Pipenv N
Poetry4 poetry.lock N
Ruby All versions Bundler
  • Gemfile.lock
  • gems.locked
Y
Scala All versions sbt5 build.sbt N
Swift All versions Swift Package Manager Package.resolved N
Cocoapods9 All versions CocoaPods Podfile.lock N
  1. Java 21 LTS sbt 仅限于版本 1.9.7。当启用 FIPS 模式时,不支持此功能。

  2. 当启用 FIPS 模式时不支持 Gradle。

  3. 对于 pnpm lockfiles 的支持引入于极狐GitLab 15.11</a>。 pnpm lockfiles 不能存储捆绑依赖,所以报告的依赖可能和 npmyarn 不同。

  4. 对于具有 poetry.lock 文件的 Poetry 项目的支持引入于极狐GitLab 15.0。

  5. 对于 sbt 1.0.x 的支持在极狐GitLab 16.8 中被弃用并在极狐GitLab 17.0 中被移除。

  6. 对低于 3.8.8 以下版本的 Maven 支持已经在极狐GitLab 16.9 中被弃用,并将在极狐GitLab 17.0 中被移除。

  7. 对于早期 Python 版本的支持在极狐GitLab 16.9 中被弃用。并在极狐GitLab 17.0 中被移除。

  8. pipsetuptools 从报告中排除,因为它们是安装程序所必需的。

  9. 仅有 SBOM,没有公告。

依赖检测

依赖扫描自动检测仓库中使用的语言。所有与检测语言相匹配的分析器都会运行。所以通常没有必须自定义分析的选择。我们不推荐指定分析器以便你可以为最佳覆盖自动使用完整的分析器选择,避免在需要弃用或移除的时候做调整。然而,你可以使用变量 DS_EXCLUDED_ANALYZERS 来进行覆盖选择。

语言检测依赖于 CI 作业 rules 并从存储库的根目录开始,最多搜索两个目录层级。 比如,如果仓库包含 Gemfileapi/Gemfileapi/client/Gemfile,则 gemnasium-dependency_scanning 作业就会被启动,但如果唯一符合支持条件的依赖项文件是 api/v1/client/Gemfile,该作业则不会被启用。

对于 Java 和 Python,当检测到支持的依赖文件时,依赖扫描就会尝试构建项目并执行一些 Java 或 Python 命令来获取依赖列表。对于其他所有的项目,lock 文件会被解析以包含依赖列表,而无需先构建项目。

当检测到支持的依赖文件时,所有的依赖,包括传递依赖项在内都要进行分析。对于所分析的嵌套依赖项或传递依赖项的深度没有限制。

如何触发分析器

极狐GitLab 依赖 rules:exists 来启动相关分析器,针对仓库中存在的 Supported files 检测到的语言,如上表所示。

当前的检测逻辑将最大搜索深度限制为两个级别。例如,如果仓库包含 Gemfile.lockapi/Gemfile.lockapi/client/Gemfile.lock,则启用 gemnasium-dependency_scanning 作业,但如果唯一支持的依赖文件是 api/v1/client/Gemfile.lock,则不然。

当检测到支持的依赖文件时,将分析所有依赖项,包括传递依赖项。分析的嵌套或传递依赖项的深度没有限制。

分析器

依赖扫描支持如下的基于 Gemnasium 的官方分析器:

  • gemnasium
  • gemnasium-maven
  • gemnasium-python

分析器以 Docker 镜像发布,依赖扫描会为每个分析发布专用的容器。你还可以集成自定义的安全扫描器

每当 Gemnasium 发布新版本的时候,分析器也会进行更新。

分析器如何获取依赖信息

极狐GitLab 使用如下两种方式中的一种来获取依赖信息:

  1. 直接解析 lockfile 文件
  2. 运行软件包管理器或构建工具来生成随后被解析的依赖信息文件

通过解析 lockfiles 来获取依赖信息

如下软件包管理器使用极狐GitLab 分析器能够处理的 lockfiles 来直接进行解析:

软件包管理器 支持的文件格式版本 测试软件包管理器版本
Bundler 不适用 1.17.3、2.1.4
Composer 不适用 1.x
Conan 0.4 1.x
Go 不适用 1.x
NuGet v1, v21 4.9
npm v1, v2, v32 6.x、7.x、9.x
pnpm v5, v6, v9 7.x、8.x、9.x
yarn versions 1, 2, 3, 43 1.x、2.x、3.x
Poetry v1 1.x
  1. 对于 NuGet 版本 2 lockfile 的支持引入于极狐GitLab 16.2。

  2. 对于 lockfileVersion = 3 的支持引入于极狐GitLab 15.7。

  3. 对于 Yarn 版本 4 的支持引入于GitLab 16.11。

    以下功能不支持 Yarn Berry:

    包含补丁、工作空间或同时包含这两者的 Yarn 文件依旧会处理,但是这些功能会被忽略。

通过运行软件包管理器来生成可解析的文件来获取依赖信息

要支持如下软件包管理器,极狐GitLab 分析器会进行以下两步:

  1. 执行软件包管理器或特定的作业来导出依赖信息。
  2. 解析导出的依赖信息。
软件包管理器 预安装的版本 测试版本
sbt 1.6.2 1.1.6、1.2.8、1.3.12、1.4.6、1.5.8、1.6.2、1.7.3、1.8.3、1.9.6、1.9.7
maven 3.9.8 3.9.81
Gradle 6.7.1</a>2、7.6.4</a>2、8.8</a>2 5.6、6.7、6.9、7.6、8.8
setuptools 70.3.0 >= 70.3.0
pip 24 24
Pipenv 2023.11.15 2023.11.15</a>3、2023.11.15
Go 1.21 1.21</a>4
  1. 此测试使用由 .tool-versions 文件指定的 maven 默认版本。

  2. Java 的不同版本需要不同版本的 Gradle。上述表中列出的 Gradle 版本都已在分析器中预安装。分析器使用的 Gradle 版本依赖你的项目是否使用 gradlew 文件:

    • 如果你的项目 没有使用 一个 gradlew 文件,然后分析器会自动切换到预安装 Gradle 版本中的一个,基于 DS_JAVA_VERSION</a> 变量指定的 Java 版本。(默认版本为 17)。

      对于 Java 811, Gradle 6.7.1 会自动被选择,Java 17 使用 Gradle 7.6.4, Java 21 使用 Gradle 8.8

    • 如果你的项目 没有使用 一个 gradlew 文件,则分析器镜像中预安装的 Gradle 版本会被忽略,从而使用在 gradlew 文件中指定的版本。

  3. 此测试会确实 Pipfile.lock 文件是否存在,Gemnasium 会使用此文件来扫描文件中列出的精确软件包版本。

  4. 由于 go build 的实现,Go build 会处理需要的网络访问,通过 go mod download 或供应商依赖预下来模块缓存。

分析器是如何被触发的

极狐GitLab 依赖于 rules:exists 来启动为检测到的语言启用的相关分析器,这些语言是通过存储库中存在的 支持的文件 来检测的,如上表所示 上表

当前的检测逻辑将最大搜索深度限制为两级。例如,如果存储库包含 Gemfile.lockapi/Gemfile.lockapi/client/Gemfile.lock,则 gemnasium-dependency_scanning 作业将被启用,但如果唯一支持的依赖文件是 api/v1/client/Gemfile.lock,则不会启用。

当检测到支持的依赖文件时,包括传递依赖项在内的所有依赖项都会被分析。对于被分析的嵌套或传递依赖项的深度没有限制。

Python

我们只在检测到需求文件或锁定文件的目录中执行一次安装。依赖关系仅由 gemnasium-python 分析检测到的第一个文件。按以下顺序搜索文件:

  1. requirements.txtrequirements.piprequires.txt 用于使用 Pip 的项目。
  2. PipfilePipfile.lock 用于使用 Pipenv 的项目。
  3. poetry.lock 用于使用 Poetry 的项目。
  4. 使用 Setuptools 的项目的setup.py

搜索从根目录开始,如果在根目录中未找到任何构建,则继续搜索子目录。因此,将在子目录中的 Pipenv 文件之前,检测到根目录中的 Poetry 锁定文件。

Java and Scala

我们只在检测到构建文件的目录中执行一个构建。对于包含多个 Gradle、Maven 或 sbt 构建或这些构建的任何组合的大型项目,gemnasium-maven 仅分析检测到的第一个构建文件的依赖关系。构建文件按以下顺序搜索:

  1. build.gradlebuild.gradle.kts 用于单个或多项目 Gradle 构建。
  2. pom.xml 用于单个或多模块 Maven 项目。
  3. build.sbt 用于单个或多项目 sbt 构建。

搜索从根目录开始,如果在根目录中未找到任何构建,则继续搜索子目录。因此,将在子目录中的 Gradle 构建文件之前,检测到根目录中的 sbt 构建文件。

JavaScript

执行以下分析器,每个分析器在处理多个文件时具有不同的行为:

  • Gemnasium

    支持多个 lockfile。

  • Retire.js

    不支持多个 lockfile。当存在多个 lockfile 时,Retire.js 会分析在按字母顺序遍历目录树时发现的第一个 lockfile。

从 14.8 版本开始,gemnasium 分析器会扫描支持的 JavaScript 项目,查找供应商库(即检入项目但不受包管理器管理的库)。

Go

支持多个文件。当检测到 go.mod 文件时,分析器会尝试使用最小版本选择。如果遇到非致命错误,分析器会回退到解析可用的 go.sum 文件。对每个检测到的 go.modgo.sum 文件重复该过程。

PHP、C、C++、.NET、C#、Ruby、JavaScript

这些语言的分析器支持多个 lockfile。

支持其它语言

在以下问题中跟踪对其他语言、依赖管理器和依赖文件的支持:

包管理器 语言 支持的文件 扫描工具
Poetry Python poetry.lock Gemnasium

配置

要启用依赖扫描,您必须包含 Dependency-Scanning.gitlab-ci.yml 模板,其作为极狐GitLab 安装的一部分提供。

启用分析器

先决条件:

  • .gitlab-ci.yml 文件中需要有一个 test 阶段。
  • 对于自部署的 runner,需要使用 dockerkubernetes 执行器。
  • 如果你正在 JihuLab.com 上使用,则默认启用。

要启用分析器,执行以下几种方式中的一种:

使用预配置的合并请求

此方法会自动准备一个在 .gitlab-ci.yml 文件中包含依赖扫描模板的合并请求。然后你将合并请求合并以启用依赖扫描。

note 此方法在没有 .gitlab-ci.yml 文件或具有少量配置文件的情况下工作良好。如果你有一个负责的极狐GitLab 配置文件,这可能会无法被成功解析,而且可能会发生错误。在这些情况下,请使用手动方法。

要启用依赖扫描:

  1. 在左侧导航栏,选择 搜索或前往 并找到你的项目。
  2. 选择 安全 > 安全配置
  3. 依赖扫描 中,选择 配置合并请求
  4. 选择 创建合并请求
  5. 查看合并请求,然后选择 合并

流水线现在包含了一个依赖扫描作业。

手动编辑 .gitlab-ci.yml 文件

此方法需要你手动编辑既有的 .gitlab-ci.yml 文件。如果你的极狐GitLab CI/CD 配置文件过于复杂,请使用此方法。

要启用依赖扫描:

  1. 在左侧导航栏,选择 搜索或前往 并找到你的项目。
  2. 选择 构建 > 流水线编辑器
  3. 如果没有 .gitlab-ci.yml 文件,选择 配置流水线,然后删除示例内容。
  4. 拷贝并粘贴下面的内容到 .gitlab-ci.yml 文件底部。如果已经存在 include,则仅添加 template 行即可。

    include:
      - template: Jobs/Dependency-Scanning.gitlab-ci.yml
    
  5. 选择 验证 选项卡,然后选择 验证流水线

    消息 模拟完成成功 确认了文件的有效性。

  6. 完成字段。不要再 分支 字段中使用默认分支。
  7. 选择 使用这些变更启动新的合并请求,然后选择 提交信息
  8. 根据你的标准工作流完成字段,然后选择 创建合并请求
  9. 根据你的标准工作流来审核并编辑合并请求,然后选择 合并

现在流水线就会包含一个依赖扫描作业了。

使用 CI/CD 组件

  • 引入于极狐GitLab 17.0。这是一个实验性功能。
  • 依赖扫描 CI/CD 组件仅支持 Android 项目。

使用 CI/CD 组件 来执行你应用程序的依赖扫描。对于使用指南,查看组件的 README 文件。

在合并请求流水线中运行作业

查看在合并请求流水线中使用安全扫描工具

自定义分析器行为

要自定义依赖扫描,使用CI/CD 变量

caution 在合并请求被合并到默认分支钱测试所有的极狐GitLab 分析器自定义变更。失败了会出现非期望的结果,包括大量的假阳性。

覆盖依赖扫描作业

要覆盖作业的定义(比如,要修改诸如 variablesdependencies 的属性),声明一个和需要覆盖作业相同名称的作业。将此作业放置在模板包含的后面并在其下面指定额外的键值。比如,为 gemnasium 分析器禁用 DS_REMEDIATE

include:
  - template: Jobs/Dependency-Scanning.gitlab-ci.yml

gemnasium-dependency_scanning:
  variables:
    DS_REMEDIATE: "false"

要覆盖 dependencies: [] 属性,在其上方添加覆盖作业,指向此属性:

include:
  - template: Jobs/Dependency-Scanning.gitlab-ci.yml

gemnasium-dependency_scanning:
  dependencies: ["build"]

可用的 CI/CD 变量

可以使用环境变量配置依赖扫描。

配置依赖扫描

以下变量允许配置全局依赖扫描设置。

caution 在将这些更改合并到默认分支之前,应在合并请求中测试极狐GitLab 安全扫描工具的所有自定义。不这样做会产生意想不到的结果,包括大量误报。
CI/CD 变量 描述
ADDITIONAL_CA_CERT_BUNDLE 要信任的 CA 证书捆绑包。此处提供的证书包也被其他工具在扫描过程中使用,例如 gityarnnpm。查看使用自定义 SSL CA 证书颁发机构,获取更多信息。
DS_EXCLUDED_ANALYZERS 指定要从依赖扫描中排除的分析器(按名称)。有关详细信息,请参阅依赖扫描分析器
DS_EXCLUDED_PATHS 根据路径从扫描中排除文件和目录,以逗号分隔的 pattern 列表。Pattern 可以是 glob(有关支持的模板,请参阅 doublestar.Match)、文件或文件夹路径(例如,doc、spec),父目录也匹配 pattern。默认值:"spec,test,tests,tmp"
DS_IMAGE_SUFFIX 后缀添加到镜像名称。如果设置为 -fips,则使用 FIPS-enabled 镜像进行扫描。有关详细信息,请参阅启用 FIPS 的镜像。引入于 14.10 版本。
SECURE_ANALYZERS_PREFIX 覆盖提供官方默认镜像(代理)的 Docker 镜像库的名称。阅读有关自定义分析器的更多信息。
SECURE_LOG_LEVEL 设置最低日志记录级别,输出此日志级别或更高级别的消息,从最高到最低严重性,日志记录级别是:fatalerrorwarninfodebug。引入于 13.1 版本,默认值:info

配置依赖扫描使用的特定分析器

以下变量用于配置特定分析器(用于特定语言/框架)。

CI/CD 变量 分析器 默认值 描述
GEMNASIUM_DB_LOCAL_PATH gemnasium /gemnasium-db 本地 Gemnasium 数据库的路径。
GEMNASIUM_DB_UPDATE_DISABLED gemnasium "false" 禁用 gemnasium-db 咨询数据库的自动更新
GEMNASIUM_DB_REMOTE_URL gemnasium 用于获取 Gemnasium 数据库的仓库 URL。
GEMNASIUM_DB_REF_NAME gemnasium master 远端仓库数据库的分支名称。需要先配置 GEMNASIUM_DB_REMOTE_URL
DS_REMEDIATE gemnasium "true",FIPS 模式中为 "false" 启用易受攻击的依赖项的自动修复。
DS_REMEDIATE_TIMEOUT gemnasium 5m 自动修复超时。
GEMNASIUM_LIBRARY_SCAN_ENABLED gemnasium "true" 启用检测供应商 JavaScript 库中的漏洞。目前,gemnasium 利用 Retire.js 来完成这项工作。引入于 14.8 版本。
DS_INCLUDE_DEV_DEPENDENCIES gemnasium "true" 当设置为 false 时,不报告开发依赖项及其漏洞。仅支持 Composer、NPM 和 Poetry 项目。引入于 15.1 版本。
GOOS gemnasium "linux" 编译 Go 代码的操作系统。
GOARCH gemnasium "amd64" 编译 Go 代码的处理器架构。
GOFLAGS gemnasium   传递给 go build 工具的标志。
GOPRIVATE gemnasium   要从源中获取的 glob pattern 和前缀列表。阅读 Go 私有模块文档,了解更多信息。
DS_JAVA_VERSION gemnasium-maven 17 Java 版本。可用版本:81117
MAVEN_CLI_OPTS gemnasium-maven "-DskipTests --batch-mode" 分析器传递给 maven 的命令行参数列表。
GRADLE_CLI_OPTS gemnasium-maven   分析器传递给 gradle 的命令行参数列表。
GRADLE_PLUGIN_INIT_PATH gemnasium-maven "gemnasium-init.gradle" 指定 Gradle 初始化脚本的路径。初始化脚本必须包含 allprojects { apply plugin: 'project-report' } 以确保兼容性。
DS_GRADLE_RESOLUTION_POLICY gemnasium-maven "failed" 控制 Gradle 依赖解决限制。接受 "none" 以允许部分结果,或当任何依赖解析失败时使用 "failed" 以让扫描失败。
SBT_CLI_OPTS gemnasium-maven   分析器传递给 sbt 的命令行参数列表。
PIP_INDEX_URL gemnasium-python https://pypi.org/simple Python 包索引的基本 URL。
PIP_EXTRA_INDEX_URL gemnasium-python   除了 PIP_INDEX_URL 之外要使用的包索引的额外 URL 数组,逗号分隔。警告: 使用此环境变量时请阅读以下安全注意事项
PIP_REQUIREMENTS_FILE gemnasium-python   要扫描的 Pip 需求文件。
PIPENV_PYPI_MIRROR gemnasium-python   如果设置,则使用镜像覆盖 Pipenv 使用的 PyPi 索引。
DS_PIP_VERSION gemnasium-python   强制安装特定的 pip 版本(例如:"19.3"),否则使用 Docker 镜像中安装的 pip。
DS_PIP_DEPENDENCY_PATH gemnasium-python   从中加载 Python pip 依赖项的路径。

其它变量

前面的表格并不是可以使用的所有变量的详尽列表,包含我们支持和测试的所有特定极狐GitLab 和分析器变量。有许多变量,例如环境变量,您可以传入并且它们会起作用。这是一个很大的列表,其中许多我们可能不知道,因此没有记录在案。

例如,要将非 GitLab 环境变量 HTTPS_PROXY 传递给所有依赖扫描作业,请将其设置为 .gitlab-ci.yml 文件中的自定义 CI/CD 变量,如下所示:

variables:
  HTTPS_PROXY: "https://squid-proxy:3128"
note Gradle 项目需要额外的变量设置来使用代理。

或者,我们可以在特定的工作中使用它,比如依赖扫描:

dependency_scanning:
  variables:
    HTTPS_PROXY: $HTTPS_PROXY

因为我们没有测试所有你可能找到的变量,所以有些能工作,有些不能工作。

自定义 TLS 证书颁发机构

依赖扫描允许为 SSL/TLS 连接使用自定义 TLS 证书,而不是使用分析器镜像中默认交付的证书。

对于自定义证书颁发机构的支持引入于以下版本:

Analyzer Version
gemnasium v2.8.0
gemnasium-maven v2.9.0
gemnasium-python v2.7.0

使用自定义 SSL CA 证书颁发机构

您可以使用 ADDITIONAL_CA_CERT_BUNDLE CI/CD 变量来配置自定义 SSL CA 证书颁发机构。ADDITIONAL_CA_CERT_BUNDLE 值应包含 X.509 PEM 公钥证书的文本表示形式

例如,要在 .gitlab-ci.yml 文件中配置此值,请使用以下命令:

variables:
  ADDITIONAL_CA_CERT_BUNDLE: |
      -----BEGIN CERTIFICATE-----
      MIIGqTCCBJGgAwIBAgIQI7AVxxVwg2kch4d56XNdDjANBgkqhkiG9w0BAQsFADCB
      ...
      jWgmPqF3vUbZE0EyScetPJquRFRKIesyJuBFMAs=
      -----END CERTIFICATE-----

认证私有 Maven 仓库

要使用需要认证的私有 Maven 仓库,你应该将凭据存储在 CI/CD 变量中并在你的 Maven 设置文件中引用它们。不要将凭据添加到你的 .gitlab-ci.yml 文件中。

要认证私有 Maven 仓库:

  1. 在你的项目设置中添加 MAVEN_CLI_OPTS CI/CD 变量,将值设置为你的凭据。

    比如,如果你的用户名是 myuser,密码是 verysecret

    类型 Key Value
    变量 MAVEN_CLI_OPTS --settings mysettings.xml -Drepository.password=verysecret -Drepository.user=myuser
  2. 使用你的服务器配置来创建一个 Maven 设置文件。

    比如,将如下内容添加到 mysettings.xml 文件中。此文件会在 MAVEN_CLI_OPTS CI/CD 变量中被引用。

    <!-- mysettings.xml -->
    <settings>
        ...
        <servers>
            <server>
                <id>private_server</id>
                <username>${private.username}</username>
                <password>${private.password}</password>
            </server>
        </servers>
    </settings>
    

FIPS-enabled 镜像

GitLab 还提供 FIPS-enabled Red Hat UBI版本的 Gemnasium 镜像。当 GitLab 实例中启用 FIPS 模式时,Gemnasium 扫描作业会自动使用 FIPS-enabled 镜像。要手动切换到 FIPS-enabled 镜像,请将变量 DS_IMAGE_SUFFIX 设置为 "-fips"

在 FIPS 模式下,不支持 Gradle 项目的依赖扫描和 Yarn 项目的自动修复。

FIPS-enabled 镜像基于 RedHat 的 UBI 微型。它们没有诸如 dnfmicrodnf 的软件包管理器因此无法在运行时安装系统软件包。

输出

依赖扫描会生成如下输出:

  • 依赖扫描报告:包含在依赖中检测到的所有漏洞详情。
  • CycloneDX 软件物料清单:每个受支持且检测到的 lock 和构建文件的软件物料清单。

依赖扫描报告

依赖扫描会输出一个包含所有漏洞详情的报告。此报告处理后展示在 UI 上。报告还会输出为依赖扫描作业的产物,名为 gl-dependency-scanning-report.json

对于依赖扫描报告的更多详情,可以查看:

CycloneDX 软件物料清单

  • 一般可用于 15.7 版本。

依赖扫描工具为它检测到的每个支持的锁定或构建文件输出一个 CycloneDX Software Bill of Materials (SBOM)。

这些 CycloneDX SBOM 会是:

  • 被命名为 gl-sbom-<package-type>-<package-manager>.json
  • 作为依赖扫描作业可用的作业产物。
  • 保存在和 lock 或构建文件的同级目录下。

例如,如果您的项目具有以下结构:

.
├── ruby-project/
│   └── Gemfile.lock
├── ruby-project-2/
│   └── Gemfile.lock
├── php-project/
│   └── composer.lock
└── go-project/
    └── go.sum

然后 Gemnasium 扫描器生成以下 CycloneDX SBOM:

.
├── ruby-project/
│   ├── Gemfile.lock
│   └── gl-sbom-gem-bundler.cdx.json
├── ruby-project-2/
│   ├── Gemfile.lock
│   └── gl-sbom-gem-bundler.cdx.json
├── php-project/
│   ├── composer.lock
│   └── gl-sbom-packagist-composer.cdx.json
└── go-project/
    ├── go.sum
    └── gl-sbom-go-go.cdx.json

合并多个 CycloneDX SBOM

你可以使用 CI/CD 作业来合并多个 CycloneDX SBOM 到单个 SBOM 中。极狐GitLab 使用 CycloneDX 属性,在每个 CycloneDX SBOM 的元数据中存储实现特定的详细信息,例如构建和锁定的文件位置。如果多个 CycloneDX SBOM 合并在一起,则此信息将从生成的合并文件中删除。

比如,如下的 .gitlab-ci.yml 演示了 CycloneDX 文件是如何被合并的,而且结果文件是经过验证的。

stages:
  - test
  - merge-cyclonedx-sboms

include:
  - template: Security/Dependency-Scanning.gitlab-ci.yml

merge cyclonedx sboms:
  stage: merge-cyclonedx-sboms
  image:
    name: cyclonedx/cyclonedx-cli:0.24.0
    entrypoint: [""]
  script:
    - find . -name "gl-sbom-*.cdx.json" -exec /cyclonedx merge --output-file gl-sbom-all.cdx.json --input-files "{}" +
  artifacts:
    paths:
      - gl-sbom-all.cdx.json

离线环境

对于受限环境下的私有化部署实例,要成功运行依赖扫描作业,需要做一些调整。更多详情,可查阅离线环境

先决条件

要在离线环境下运行依赖扫描,你必须要:

  • 使用 dockerkubernetes 执行器的极狐GitLab Runner
  • 依赖扫描分析器镜像的本地拷贝

分析器镜像的本地拷贝

要使用所有支持的语言和框架的依赖扫描:

  1. registry.gitlab.com 导入以下默认的依赖扫描分析器镜像到 你的本地Docker容器注册表中:

    registry.gitlab.com/security-products/gemnasium:5
    registry.gitlab.com/security-products/gemnasium:5-fips
    registry.gitlab.com/security-products/gemnasium-maven:5
    registry.gitlab.com/security-products/gemnasium-maven:5-fips
    registry.gitlab.com/security-products/gemnasium-python:5
    registry.gitlab.com/security-products/gemnasium-python:5-fips
    

    将Docker镜像导入到本地离线Docker注册表中的过程取决于 你的网络安全策略。请与你的IT人员联系,了解外部资源可以被导入或临时访问的接受和批准的过程。 这些扫描器会定期更新 新的定义,你可能想定期下载它们。

  2. 配置GitLab CI/CD以使用本地分析器。

    将CI/CD变量 SECURE_ANALYZERS_PREFIX 的值设置为你的本地Docker注册表 - 在 这个例子中,docker-registry.example.com

    include:
      - template: Jobs/Dependency-Scanning.gitlab-ci.yml
    
    variables:
      SECURE_ANALYZERS_PREFIX: "docker-registry.example.com/analyzers"
    

访问GitLab Advisory Database

GitLab Advisory Databasegemnasium, gemnasium-maven, 和 gemnasium-python 分析器使用的漏洞数据源。这些分析器的Docker镜像包含数据库的克隆。 在开始扫描之前,克隆会与数据库同步,以确保分析器拥有最新的漏洞数据。

在离线环境中,默认的GitLab Advisory Database主机不能被访问。 相反,你必须在GitLab运行器可以访问的地方托管数据库。你还必须根据自己的计划手动更新数据库。

托管数据库的可用选项是:

使用GitLab Advisory Database的克隆

使用GitLab Advisory Database的克隆是推荐的,因为这是最有效的方法。

要托管GitLab Advisory Database的克隆:

  1. 将GitLab Advisory Database克隆到GitLab运行器可以通过HTTP访问的主机上。
  2. 在你的.gitlab-ci.yml文件中,设置CI/CD变量 GEMNASIUM_DB_REMOTE_URL 的值为 Git存储库的URL。

例如:

variables:
  GEMNASIUM_DB_REMOTE_URL: https://users-own-copy.example.com/gemnasium-db.git

使用GitLab Advisory Database 的副本

使用 GitLab Advisory Database 的副本需要你托管一个存档文件,该文件将被分析器下载。

要使用 GitLab Advisory Database 的副本:

  1. 从 GitLab Advisory Database 下载一个存档文件到GitLab运行器可以通过HTTP访问的主机上。存档文件位于 https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/archive/master/gemnasium-db-master.tar.gz
  2. 更新你的.gitlab-ci.yml文件。

    • 设置CI/CD变量 GEMNASIUM_DB_LOCAL_PATH 使用数据库的本地副本。
    • 设置CI/CD变量 GEMNASIUM_DB_UPDATE_DISABLED 禁用数据库更新。
    • 在扫描开始之前下载并提取咨询数据库。
    variables:
      GEMNASIUM_DB_LOCAL_PATH: ./gemnasium-db-local
      GEMNASIUM_DB_UPDATE_DISABLED: "true"
    
    dependency_scanning:
      before_script:
        - wget https://local.example.com/gemnasium_db.tar.gz
        - mkdir -p $GEMNASIUM_DB_LOCAL_PATH
        - tar -xzvf gemnasium_db.tar.gz --strip-components=1 -C $GEMNASIUM_DB_LOCAL_PATH
    

使用Gradle项目的代理

Gradle wrapper脚本不读取 HTTP(S)_PROXY 环境变量。见这个上游问题

要使Gradle wrapper脚本使用代理,可以使用 GRADLE_CLI_OPTS CI/CD变量指定选项:

variables:
  GRADLE_CLI_OPTS: "-Dhttps.proxyHost=squid-proxy -Dhttps.proxyPort=3128 -Dhttp.proxyHost=squid-proxy -Dhttp.proxyPort=3128 -Dhttp.nonProxyHosts=localhost"

使用Maven项目的代理

Maven不读取 HTTP(S)_PROXY 环境变量。

要使Maven依赖项扫描器使用代理,可以使用 settings.xml 文件(见Maven文档)配置,并通过使用 MAVEN_CLI_OPTS CI/CD变量来指示Maven使用这个配置:

variables:
  MAVEN_CLI_OPTS: "--settings mysettings.xml"

特定语言和包管理器的设置

见以下部分,了解如何为特定语言和包管理器进行配置。

Python (pip)

如果你需要在分析器运行之前安装Python包,你应该在扫描作业的 before_script 中使用 pip install --user--user 标志导致项目依赖项被安装在用户目录中。如果你不传递 --user 选项,包将被全局安装,并且它们不会被扫描和列出项目依赖项。

Python (setuptools)

如果你需要在分析器运行之前安装Python包,你应该在扫描作业的 before_script 中使用 python setup.py install --user--user 标志导致项目依赖项被安装在用户目录中。如果你不传递 --user 选项,包将被全局安装,并且它们不会被扫描和列出项目依赖项。

当使用自签名证书为你的私有PyPi仓库时,除了上述模板 .gitlab-ci.yml 之外,不需要额外的作业配置。然而,你必须更新你的 setup.py,以确保它可以访问你的私有仓库。以下是一个示例配置:

  1. 更新 setup.py,为每个在 install_requires 列表中的依赖项创建一个 dependency_links 属性,指向你的私有仓库:

    install_requires=['pyparsing>=2.0.3'],
    dependency_links=['https://pypi.example.com/simple/pyparsing'],
    
  2. 从你的仓库URL中获取证书,并将其添加到项目中:

    printf "\n" | openssl s_client -connect pypi.example.com:443 -servername pypi.example.com | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > internal.crt
    
  3. 指向 setup.py 中的新下载的证书:

    import setuptools.ssl_support
    setuptools.ssl_support.cert_paths = ['internal.crt']
    

Python (Pipenv)

如果在网络连接性有限的环境中运行,你必须配置 PIPENV_PYPI_MIRROR 变量,以使用私有PyPi镜像。这个镜像必须包含默认和开发依赖项。

variables:
  PIPENV_PYPI_MIRROR: https://pypi.example.com/simple

或者,如果不可能使用私有注册表,你可以将所需的包加载到Pipenv虚拟环境缓存中。对于这个选项,项目必须将 Pipfile.lock 检入到存储库中,并加载默认和开发包到缓存中。见python-pipenv 项目的示例,了解如何完成这项工作。

告警

我们建议您使用所有容器和所有包管理器及语言的最新支持版本。使用以前的版本会增加安全风险,因为不再支持的版本可能不再受益于活跃的安全报告和安全修复的回溯。

Gradle 项目

在为 Gradle 项目生成 HTML 依赖报告时,不要覆盖 reports.html.destinationreports.html.outputLocation 属性。这样做会导致依赖扫描无法正常工作。

Maven 项目

在隔离网络中,如果中央仓库是一个私有注册表(使用 <mirror> 指令明确设置),Maven 构建可能无法找到 gemnasium-maven-plugin 依赖项。这个问题的原因是 Maven 默认不会搜索本地仓库(/root/.m2)并尝试从中央仓库获取。结果是一个关于缺少依赖项的错误。

解决方法

要解决这个问题,需要在你的 settings.xml 文件中添加一个 <pluginRepositories> 部分。这样可以让 Maven 在本地仓库中找到插件。

在开始之前,请考虑以下事项:

  • 这个解决方法只适用于默认 Maven 中央仓库被镜像到私有注册表的环境。
  • 应用这个解决方法后,Maven 会在本地仓库中搜索插件,这可能在某些环境中有安全风险。确保这符合你的组织的安全政策。 按照以下步骤修改 settings.xml 文件:
  1. 定位你的 Maven settings.xml 文件。这个文件通常位于以下位置之一:

    • /root/.m2/settings.xml,用于根用户。
    • ~/.m2/settings.xml,用于普通用户。
    • ${maven.home}/conf/settings.xml,用于全局设置。
  2. 检查文件中是否已存在 <pluginRepositories> 部分。

  3. 如果已存在 <pluginRepositories> 部分,则只在其中添加以下 <pluginRepository> 元素。否则,添加整个 <pluginRepositories> 部分:

         <pluginRepositories>
           <pluginRepository>
               <id>local2</id>
               <name>本地仓库</name>
               <url>file:///root/.m2/repository/</url>
           </pluginRepository>
         </pluginRepositories>
    
  4. 再次运行你的 Maven 构建或依赖项扫描过程。

Python 项目

当使用 PIP_EXTRA_INDEX_URL 环境变量时,需要额外小心,因为漏洞 CVE-2018-20225:

版本号解析

在有些情况下,无法确定项目依赖项的版本是否处于安全公告所涉及的受影响范围内。

比如:

  • 版本是未知的。
  • 版本是有效的。
  • 解析版本或将其和范围内进行对比时失败。
  • 版本是一个分支,诸如 dev-master1.5.x
  • 对比的版本是不确定的。比如,1.0.0-20241502 无法和 1.0.0-2 对比,因为一个版本包含时间戳,而另外一个未包含。

在这些情况下,分析器会跳过依赖并将消息输出到日志中。

极狐GitLab 分析器不会进行无端假设,因为这些假设可能会导致误报或漏报。

构建 Swift 项目

Swift 包管理器(SPM)是管理 Swift 代码发行版的官方工具。它和 Swift 构建系统进行了集成以自动化处理依赖的下载、便衣和链接。

当使用 SPM 构建 Swift 项目时,可遵循以下最佳实践。

  1. 包含一个 Package.resolved 文件。

    Package.resolved 文件会将依赖锁定到指定版本。总是将此文件条件到仓库中能够确保在不同环境下的一致性。

    git add Package.resolved
    git commit -m "Add Package.resolved to lock dependencies"
    
  2. 使用如下命令构建 Swift 项目:

    # Update dependencies
    swift package update
    
    # Build the project
    swift build
    
  3. 要配置 CI/CD,将这些步骤添加到你的 .gitlab-ci.yml 文件中:

    swift-build:
      stage: build
      script:
        - swift package update
        - swift build
    
  4. 可选。如果你使用自签名的私有 Swift 软件包仓库,你可能需要将证书添加到你的项目中并配置 Swift 来信任它们:

    1. 获取证书:

      echo | openssl s_client -servername your.repo.url -connect your.repo.url:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END
      CERTIFICATE-/p' > repo-cert.crt
      
    2. 将下面内容调价到你的 Swift软件包清单中 (Package.swift):

      import Foundation
      
      #if canImport(Security)
      import Security
      #endif
      
      extension Package {
          public static func addCustomCertificate() {
              guard let certPath = Bundle.module.path(forResource: "repo-cert", ofType: "crt") else {
                  fatalError("Certificate not found")
              }
              SecCertificateAddToSystemStore(SecCertificateCreateWithData(nil, try! Data(contentsOf: URL(fileURLWithPath: certPath)) as CFData)!)
          }
      }
      
      // Call this before defining your package
      Package.addCustomCertificate()
      

要总是在干净的环境下测试你的构建以确保你的依赖被正确指定而且能够被自动分析。

构建 CocoaPods 项目

CocoaPods 是一个针对 Swift 和 Objective-C Cocoa 项目的流行依赖管理器。它能够提供在 iOS、macOS、watchOS 和 tvOS 项目中管理外部库的标准格式。

当你使用 CocoaPods 来进行依赖管理并构建项目时,可遵循如下最佳实践。

  1. 包含一个 Podfile.lock 文件。

    Podfile.lock 文件对于你为指定版本锁定依赖来说非常重要。将此文件总是添加到你的仓库中来确保不同环境下的一致性。

    git add Podfile.lock
    git commit -m "Add Podfile.lock to lock CocoaPods dependencies"
    
  2. 你可以使用如下方式来构建你的项目:

    • xcodebuild 命令行工具:

      # Install CocoaPods dependencies
      pod install
      
      # Build the project
      xcodebuild -workspace YourWorkspace.xcworkspace -scheme YourScheme build
      
    • Xcode IDE:

      1. 在 Xcode 中打开你的 .xcworkspace 文件。
      2. 选择目标格式。
      3. 选择 产品 > 构建。你可以按 +B
    • fastlane,一个为 iOS 和 Android 应用程序构建和发布应用的自动化工具:

      1. Install fastlane:

        sudo gem install fastlane
        
      2. 在你的项目中,配置 fastlane

        fastlane init
        
      3. 添加 lane 到 fastfile

        lane :build do
          cocoapods
          gym(scheme: "YourScheme")
        end
        
      4. 运行构建:

        fastlane build
        
    • 如果你的项目在同时使用 CocoaPods 和 Carthage,你可以使用 Carthage 来构建你的依赖:

      1. 创建一个包含你 CocoaPods 依赖的 Cartfile 文件。
      2. 运行如下命令:

        carthage update --platform iOS
        
  3. 配置 CI/CD 来根据你偏爱的方法来构建项目。

    比如,使用 xcodebuild

    cocoapods-build:
      stage: build
      script:
        - pod install
        - xcodebuild -workspace YourWorkspace.xcworkspace -scheme YourScheme build
    
  4. 可选。如果你使用私有的 CocoaPods 仓库,你可能需要配置你的项目来访问它们:

    1. 添加私有说明仓库:

      pod repo add REPO_NAME SOURCE_URL
      
    2. 在你的 Podfile,指定源:

      source 'https://github.com/CocoaPods/Specs.git'
      source 'SOURCE_URL'
      
  5. 可选。如果你的私有 CocoaPods 仓库使用 SSL,确保正确配置了 SSL 证书:

    • 如果你使用自签名证书,将其添加到你系统的受信任证书中。你还可以在你的 .netrc 文件中指定 SSL 配置:

      machine your.private.repo.url
        login your_username
        password your_password
  6. 在你更新 Podfile 后,运行 pod install t来安装并更新你的工作空间。

切记,在更新 Podfile 后总是要运行 pod install 以确保所有的依赖都被正确安装而且工作空间已被更新。