Help us learn about your current experience with the documentation. Take the survey.

依赖扫描

  • Tier: Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

基于Gemnasium分析器的依赖扫描功能在GitLab 17.9中已弃用,并计划在GitLab 19.0中移除。它正被使用SBOM的依赖扫描新的依赖扫描分析器取代。更多信息请参阅史诗任务15961

依赖扫描会在应用程序的依赖项到达生产环境前识别其中的安全漏洞。这种识别可保护您的应用免受潜在利用和数据泄露的影响,避免损害用户信任和业务声誉。当在流水线运行中发现漏洞时,它们会直接显示在您的合并请求中,让您在代码提交前立即了解安全问题。

您代码中的所有依赖项(包括传递性(嵌套)依赖项)都会在流水线期间自动进行分析。此分析能捕捉到人工审查流程可能遗漏的安全问题。依赖扫描只需少量配置更改即可集成到现有的CI/CD工作流中,使您从一开始就能轻松实施安全开发实践。

漏洞也可通过持续漏洞扫描在流水线外识别。

GitLab同时提供依赖扫描和容器扫描,以确保覆盖所有这些依赖类型。为了尽可能覆盖您的风险区域,我们鼓励您使用我们所有的安全扫描器。有关这些功能的比较,请参阅依赖扫描与容器扫描对比

依赖扫描小部件

依赖扫描不支持运行时安装编译器和解释器。

开始使用

要开始使用依赖扫描,以下步骤展示了如何为项目启用依赖扫描。

先决条件:

  • .gitlab-ci.yml文件中需要有test阶段。
  • 使用自托管Runner时,需要一个带有dockerkubernetes执行器的GitLab Runner。
  • 如果您在使用GitLab.com上的SaaS Runner,则默认启用此功能。

要启用分析器,可以:

使用预配置的合并请求

这种方法会自动准备一个包含依赖扫描模板的合并请求到 .gitlab-ci.yml 文件中。随后你合并该合并请求即可启用依赖扫描。

这种方法最适合无现有 .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. 按标准流程填写字段后,选择 创建合并请求

  10. 按标准流程审核编辑合并请求,最后选择 合并

现在流水线中已包含依赖扫描任务。

使用 CI/CD 组件

使用 CI/CD 组件 对应用执行依赖扫描。操作指南见对应组件的 README 文件。

可用的 CI/CD 组件

参见 https://gitlab.com/explore/catalog/components/dependency-scanning

完成上述步骤后,你可:

理解结果

你可在流水线中查看漏洞:

  1. 左侧边栏中选择 搜索或前往 并找到项目。
  2. 左侧边栏中选择 构建 > 流水线
  3. 选择目标流水线。
  4. 点击 安全 选项卡。
  5. 选择漏洞查看详情,包括:
    • 状态:表明漏洞是否已分类或解决。
    • 描述:解释漏洞成因、潜在影响及修复建议。
    • 严重程度:按影响分六级。了解严重程度层级
    • CVSS 分数:映射严重程度的数值。
    • EPSS:显示漏洞在野外的利用可能性。
    • 已知漏洞(KEV):表示漏洞已被利用。
    • 项目:标注发现漏洞的项目。
    • 报告类型 / 扫描器:说明输出类型及所用扫描器。
    • 可达性:指示脆弱依赖是否在代码中使用。
    • 扫描器:识别检测漏洞的分析工具。
    • 位置:命名含脆弱依赖的文件。
    • 链接:漏洞在各咨询库中的编目证据。
    • 标识符:用于分类漏洞的引用(如 CVE 标识符)。

依赖扫描生成以下输出:

  • 依赖扫描报告:包含所有检测到的依赖漏洞详情。
  • CycloneDX 软件物料清单:各支持的锁文件或构建文件对应的软件物料清单(SBOM)。

依赖扫描报告

依赖扫描会输出一份包含所有漏洞详细信息的报告。该报告会在内部进行处理,结果会显示在 UI 中。这份报告也会作为依赖扫描作业的产物输出,命名为 gl-dependency-scanning-report.json

若需了解依赖扫描报告的更多细节,请参阅 依赖扫描报告架构

CycloneDX 软件物料清单(SBOM)

依赖扫描会对检测到的每个支持的锁文件或构建文件,输出一份 CycloneDX 软件物料清单(SBOM)。

这些 CycloneDX SBOM 具有以下特点:

  • 命名为 gl-sbom-<包类型>-<包管理器>.cdx.json
  • 可作为依赖扫描作业的产物获取。
  • 保存在与检测到的锁文件或构建文件相同的目录中。

例如,如果你的项目结构如下:

.
├── 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 片段演示了如何合并 Cyclone SBOM 文件并对结果文件进行验证:

stages:
  - test
  - merge-cyclonedx-sboms

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

merge cyclonedx sboms:
  stage: merge-cyclonedx-sboms
  image:
    name: cyclonedx/cyclonedx-cli:0.25.1
    entrypoint: [""]
  script:
    - find . -name "gl-sbom-*.cdx.json" -exec cyclonedx merge --output-file gl-sbom-all.cdx.json --input-files "{}" +
    # 可选:验证合并后的 sbom
    - cyclonedx validate --input-version v1_4 --input-file gl-sbom-all.cdx.json
  artifacts:
    paths:
      - gl-sbom-all.cdx.json

推广阶段

当你对单个项目的依赖扫描结果有信心后,可以将其实施扩展到其他项目中:

支持的语言和包管理器

依赖扫描(Dependency Scanning)支持以下语言和依赖管理工具:

语言 语言版本 包管理器 支持的文件 是否处理多个文件?
.NET 所有版本 NuGet packages.lock.json
C#
C 所有版本 Conan conan.lock
C++
Go 所有版本 Go
  • go.mod
Java 和 Kotlin 8 LTS, 11 LTS, 17 LTS, 或 21 LTS1 Gradle2
  • build.gradle
  • build.gradle.kts
Maven6 pom.xml
JavaScript 和 TypeScript 所有版本 npm
  • package-lock.json
  • npm-shrinkwrap.json
yarn yarn.lock
pnpm3 pnpm-lock.yaml
PHP 所有版本 Composer composer.lock
Python 3.117 setuptools8 setup.py
pip
  • requirements.txt
  • requirements.pip
  • requires.txt
Pipenv
Poetry4 poetry.lock
uv uv.lock
Ruby 所有版本 Bundler
  • Gemfile.lock
  • gems.locked
Scala 所有版本
```html
语言 支持的版本 包管理器 锁定文件 支持依赖扫描
sbt5 所有版本 sbt build.sbt N
Swift 所有版本 Swift Package Manager Package.resolved N
Cocoapods9 所有版本 CocoaPods Podfile.lock N
Dart10 所有版本 Pub pubspec.lock N
  1. 对于 sbt 的 Java 21 LTS 仅限于版本 1.9.7。更多 sbt 版本的支持情况可以在 问题 430335 中跟踪。 当启用 FIPS 模式 时,不支持此功能。

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

  3. pnpm 锁定文件的支持是在 GitLab 15.11 中引入的。pnpm 锁定文件不存储捆绑依赖项,因此报告的依赖项可能与 npmyarn 不同。

  4. 支持 Poetry 项目(带有 poetry.lock 文件)的功能是在 GitLab 15.0 中添加的。 对没有 poetry.lock 文件的项目支持正在跟踪中:请参见问题 Poetry 的 pyproject.toml 支持依赖扫描。

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

  6. Maven 低于 3.8.8 的支持在 GitLab 16.9 中被弃用,并将在 GitLab 17.0 中移除。

  7. 之前版本的 Python 支持在 GitLab 16.9 中被弃用,并在 GitLab 17.0 中移除。

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

  9. 仅支持 SBOM,不支持建议。请参阅 关于 CocoaPods 建议研究的 spike

  10. 尚未支持许可证检测。请参阅 关于 Dart 许可证检测的 epic

```

在合并请求管道中运行作业

请参阅 在合并请求管道中使用安全扫描工具

自定义分析器行为

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

在将这些更改合并到默认分支之前,请在合并请求中测试所有 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 变量

您可以使用 CI/CD 变量来 自定义 依赖项扫描行为。

全局分析器设置

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

CI/CD 变量 说明
ADDITIONAL_CA_CERT_BUNDLE 要信任的 CA 证书包。此处提供的证书包在扫描过程中也会被其他工具使用,如 gityarnnpm。有关更多详细信息,请参见 自定义 TLS 证书颁发机构
DS_EXCLUDED_ANALYZERS 指定要从依赖项扫描中排除的分析器(按名称)。有关更多信息,请参见 分析器
DS_EXCLUDED_PATHS 基于路径排除文件和目录进行扫描。逗号分隔的模式列表。模式可以是 glob(支持的模式请参见 doublestar.Match),也可以是文件或文件夹路径(例如 doc,spec)。父目录也匹配这些模式。这是在执行扫描前应用的预过滤器。默认值:"spec, test, tests, tmp"
DS_IMAGE_SUFFIX 添加到镜像名称的后缀。(GitLab 团队成员可以在机密问题中查看更多信息:https://gitlab.com/gitlab-org/gitlab/-/issues/354796)。当启用 FIPS 模式时自动设置为 "-fips"
DS_MAX_DEPTH 定义分析器应搜索受支持文件的目录深度级别。值为 -1 时,无论深度如何都扫描所有目录。默认值:2
SECURE_ANALYZERS_PREFIX 覆盖提供官方默认图像(代理)的 Docker 注册表名称。

分析器特定设置

以下变量配置特定依赖扫描分析器的行为。

CI/CD 变量 分析器 默认值 说明
GEMNASIUM_DB_LOCAL_PATH gemnasium /gemnasium-db 本地 Gemnasium 数据库的路径。
GEMNASIUM_DB_UPDATE_DISABLED gemnasium "false" 禁用 gemnasium-db 建议数据库的自动更新。用法请参见 访问 GitLab 建议数据库
GEMNASIUM_DB_REMOTE_URL gemnasium https://gitlab.com/gitlab-org/security-products/gemnasium-db.git 获取 GitLab 建议数据库的仓库 URL。
GEMNASIUM_DB_REF_NAME gemnasium master 远程仓库数据库的分支名称。需提供 GEMNASIUM_DB_REMOTE_URL
GEMNASIUM_IGNORED_SCOPES gemnasium 要忽略的 Maven 依赖作用域的逗号分隔列表。更多详情,请参阅 Maven 依赖作用域文档
DS_REMEDIATE gemnasium "true"(FIPS 模式下为 "false" 启用易受攻击依赖项的自动修复。FIPS 模式下不受支持。
DS_REMEDIATE_TIMEOUT gemnasium 5m 自动修复的超时时间。
GEMNASIUM_LIBRARY_SCAN_ENABLED gemnasium "true" 启用对供应商 JavaScript 库(非包管理器管理的库)中漏洞的检测。此功能要求提交中存在 JavaScript 锁定文件,否则不会执行依赖扫描且不扫描供应商文件。
依赖扫描使用 Retire.js 扫描器检测有限数量的漏洞。有关检测到的漏洞详情,请参阅 Retire.js 仓库
DS_INCLUDE_DEV_DEPENDENCIES gemnasium "true" 当设置为 "false" 时,开发依赖及其漏洞不会被报告。仅支持使用 Composer、Maven、npm、pnpm、Pipenv 或 Poetry 的项目。GitLab 15.1 引入
GOOS gemnasium "linux" 编译 Go 代码的目标操作系统。
GOARCH gemnasium "amd64" 编译 Go 代码的处理器架构。
GOFLAGS gemnasium 传递给 go build 工具的标志。
GOPRIVATE gemnasium 要从源获取的 glob 模式和前缀列表。更多信息,请参阅 Go 私有模块 文档
DS_JAVA_VERSION gemnasium-maven 17 Java 版本。可用版本:8111721
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 初始化脚本的路径。init 脚本必须包含 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"

Gradle 项目需要 额外的变量设置 才能使用代理。

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

dependency_scanning:
  variables:
    HTTPS_PROXY: $HTTPS_PROXY

由于我们尚未测试所有变量,你可能会发现有些有效而有些无效。如果一个变量不起作用但你又需要它,我们建议 提交功能请求 或贡献代码以启用其使用。

自定义 TLS 证书颁发机构

依赖扫描允许使用自定义 TLS 证书来建立 SSL/TLS 连接,而非使用分析器容器镜像中默认附带的证书。

对自定义证书颁发机构的支持是在以下版本中引入的。

分析器 版本
gemnasium v2.8.0
gemnasium-maven v2.9.0
gemnasium-python v2.7.0

使用自定义 TLS 证书颁发机构

若要使用自定义 TLS 证书颁发机构,需将 X.509 PEM 公钥证书的文本表示 分配给 CI/CD 变量 ADDITIONAL_CA_CERT_BUNDLE

例如,在 .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

    类型
    Variable 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>${repository.user}</username>
                <password>${repository.password}</password>
            </server>
        </servers>
    </settings>

启用FIPS的镜像

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

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

启用 FIPS 的镜像基于 RedHat 的 UBI 微镜像。它们没有像 dnfmicrodnf 这样的包管理器,因此无法在运行时安装系统软件包。

离线环境

  • 层级:Ultimate
  • 提供:GitLab 自托管(Self-Managed)

对于在网络环境中对互联网外部资源访问受限、受限制或不稳定的情况,依赖项扫描作业需要一些调整才能成功运行。更多信息,请参阅 离线环境

要求

要在离线环境中运行依赖项扫描,您必须具备以下条件:

本地分析器镜像副本

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

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

    registry.gitlab.com/security-products/gemnasium:6
    registry.gitlab.com/security-products/gemnasium:6-fips
    registry.gitlab.com/security-products/gemnasium-maven:6
    registry.gitlab.com/security-products/gemnasium-maven:6-fips
    registry.gitlab.com/security-products/gemnasium-python:6
    registry.gitlab.com/security-products/gemnasium-python:6-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 安全公告数据库

GitLab 安全公告数据库gemnasiumgemnasium-mavengemnasium-python 分析器使用的漏洞数据来源。这些分析器的 Docker 镜像包含该数据库的克隆。在开始扫描前,克隆会与数据库同步,以确保分析器拥有最新的漏洞数据。

在离线环境中,无法访问 GitLab 安全公告数据库的默认主机。相反,您必须在可被 GitLab Runner 访问的地方托管该数据库。您还必须按照自己的计划手动更新数据库。

托管数据库的可选方案包括:

使用 GitLab 安全公告数据库的克隆

使用 GitLab 安全公告数据库的克隆是推荐方法,因为它最高效。

要托管 GitLab 安全公告数据库的克隆:

  1. 将 GitLab 安全公告数据库克隆到一个可通过 HTTP 从 GitLab Runner 访问的主机上。
  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 漏洞数据库的副本

使用 GitLab 漏洞数据库的副本需要你托管一个归档文件,该文件由分析器下载。

若要使用 GitLab 漏洞数据库的副本:

  1. 将 GitLab 漏洞数据库的归档文件下载到可通过 HTTP 被 GitLab runner 访问的主机上。该归档文件位于 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 包装器脚本不会读取 HTTP(S)_PROXY 环境变量。参见 此上游问题

若要让 Gradle 包装器脚本使用代理,你可以通过 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 项目。

依赖项检测

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

语言检测依赖于CI作业的rules来检测受支持的依赖文件

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

所有直接和传递依赖项都会被分析,对传递依赖项的深度没有限制。

分析器

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

  • gemnasium
  • gemnasium-maven
  • gemnasium-python

这些分析器作为Docker镜像发布,依赖项扫描使用它们为每次分析启动专用容器。你也可以集成一个自定义的安全扫描器。

每当Gemnasium的新版本发布时,每个分析器都会更新。

分析器如何获取依赖项信息

GitLab分析器通过以下两种方法之一获取依赖项信息:

  1. 直接解析lock文件。
  2. 运行包管理器或构建工具生成可解析的依赖项信息文件,然后进行解析。

通过解析锁定文件获取依赖信息

以下包管理器使用 GitLab 分析器能够直接解析的锁定文件:

包管理器 支持的文件格式版本 测试过的包管理器版本
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 版本 1, 2, 3, 43 1.x, 2.x, 3.x
Poetry v1 1.x
uv v0.x 0.x
  1. 对 NuGet 版本 2 锁定文件的支持已在 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.12, 7.6.42, 8.82 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.153, 2023.11.15
      Go 1.21 1.214
      1. 此测试使用.tool-versions文件中指定的默认版本的maven

      2. 不同版本的Java需要不同版本的Gradle。上表中列出的Gradle版本已预装在分析器镜像中。分析器使用的Gradle版本取决于您的项目是否使用gradlew(Gradle包装器)文件:

        • 如果您的项目不使用gradlew文件,则分析器会根据DS_JAVA_VERSION变量(默认版本为17)指定的Java版本,自动切换到其中一个预装的Gradle版本。

          对于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构建过程需要网络访问、通过go mod download预先加载的mod缓存或vendored依赖项。更多信息请参阅Go文档中关于编译包及其依赖项的内容。

      分析器如何被触发

      GitLab 依赖于 rules:exists 来启动相关分析器,这些分析器针对的是通过仓库中存在 受支持的文件 检测到的语言。 从仓库根目录开始最多搜索两层目录。例如,若仓库包含 Gemfileapi/Gemfileapi/client/Gemfile,则启用 gemnasium-dependency_scanning 任务;但如果唯一受支持的依赖文件是 api/v1/client/Gemfile,则不会启用。

      多个文件的处理方式

      如果在扫描多个文件时遇到问题,请在 此问题 中留言反馈。

      Python

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

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

      搜索从根目录开始,若根目录无匹配文件,则继续搜索子目录。因此,根目录下的 Poetry 锁文件会在子目录中的 Pipenv 文件之前被检测到。

      Java 和 Scala

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

      1. 单一或 多模块 Maven 项目:pom.xml
      2. 单一或 多项目 Gradle 构建:build.gradlebuild.gradle.kts
      3. 单一或 多项目 sbt 构建:build.sbt

      搜索从根目录开始,若根目录无匹配文件,则继续搜索子目录。因此,根目录下的 sbt 构建文件会在子目录中的 Gradle 构建文件之前被检测到。 对于 多模块 Maven 项目,以及多项目 Gradlesbt 构建,若子模块和子项目文件在父构建文件中被声明,则会进行分析。

      JavaScript

      会执行以下分析器,它们在处理多个文件时的行为不同:

      • Gemnasium

        支持多个锁文件

      • Retire.js

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

      gemnasium 分析器会扫描 JavaScript 项目中的 vendor 库(即检入项目但未被包管理器管理的库)。

      Go

      支持多个文件。当检测到 go.mod 文件时,分析器会尝试使用 Minimal Version Selection 生成 build 列表。若失败,分析器会转而解析 go.mod 文件内的依赖项。

      要求:需使用 go mod tidy 命令清理 go.mod 文件以确保依赖项正确管理。对每个检测到的 go.mod 文件重复此过程。

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

      这些语言的分析器支持多个锁文件。

      额外语言的支持

      额外语言、依赖管理器和依赖文件的支持跟踪于以下问题:

      包管理器 语言 受支持文件 扫描工具 问题
      Poetry Python pyproject.toml Gemnasium GitLab#32774
      ## 警告
      
      我们建议您使用所有容器的最新版本,以及所有包管理器和语言的最新受支持版本。使用旧版本会增加安全风险,因为不受支持的版本可能不再受益于主动的安全报告和安全补丁的反向移植。
      
      ### Gradle 项目
      
      在为 Gradle 项目生成 HTML 依赖报告时,**不要覆盖** `reports.html.destination``reports.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`
      1. 检查文件中是否存在现有的 `<pluginRepositories>` 部分。
      
      1. 如果已存在 `<pluginRepositories>` 部分,只需在该部分内添加以下 `<pluginRepository>` 元素;否则,添加整个 `<pluginRepositories>` 部分:
      
         ```xml
           <pluginRepositories>
             <pluginRepository>
                 <id>local2</id>
                 <name>本地仓库</name>
                 <url>file:///root/.m2/repository/</url>
             </pluginRepository>
           </pluginRepositories>
      1. 再次运行 Maven 构建 或 依赖扫描流程。

      Python 项目

      由于 CVE-2018-20225 记录的可能漏洞,使用 PIP_EXTRA_INDEX_URL 环境变量时需格外谨慎:

      pip(所有版本)中发现一个问题,因为它安装版本号最高的版本,即使用户原本打算从私有索引获取私有包。这仅影响 PIP_EXTRA_INDEX_URL 选项的使用,且利用此漏洞要求该包尚未存在于公共索引中(因此攻击者可在其中放置具有任意版本号的包)。

      版本号解析

      在某些情况下,无法确定项目依赖项的版本是否在安全公告的影响范围内。例如:

      • 版本未知。
      • 版本无效。
      • 解析版本或与范围比较失败。
      • 版本是分支,如 dev-master1.5.x
      • 比较的版本模糊不清。例如,1.0.0-20241502 无法与 1.0.0-2 比较,因为一个版本包含时间戳而另一个不包含。

      在这些情况下,分析器会跳过该依赖项并向日志输出消息。

      GitLab 分析器不会做出假设,因为这可能导致误报或漏报。有关讨论,请参阅 问题 442027

      
      ## 构建 Swift 项目
      
      Swift Package Manager (SPM) 是管理 Swift 代码分发的官方工具。
      它集成到 Swift 构建系统中,自动完成下载、编译和链接依赖的过程。
      
      使用 SPM 构建 Swift 项目时,遵循以下最佳实践。
      
      1. 包含一个 `Package.resolved` 文件。
      
         `Package.resolved` 文件将你的依赖锁定到特定版本。
         始终将该文件提交到仓库,以确保不同环境的一致性。
      
         ```shell
         git add Package.resolved
         git commit -m "添加 Package.resolved 以锁定依赖"
      1. 要构建你的 Swift 项目,使用以下命令:

        # 更新依赖
        swift package update
        
        # 构建项目
        swift build
      2. 若要配置 CI/CD,将这些步骤添加到你的 .gitlab-ci.yml 文件中:

        swift-build:
          stage: build
          script:
            - swift package update
            - swift build
      3. 可选。如果你使用带有自签名证书的私有 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("未找到证书")
                  }
                  SecCertificateAddToSystemStore(SecCertificateCreateWithData(nil, try! Data(contentsOf: URL(fileURLWithPath: certPath)) as CFData)!)
              }
          }
          
          // 在定义包之前调用此方法
          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 "添加 Podfile.lock 以锁定 CocoaPods 依赖项"
      2. 您可以使用以下方法之一构建项目:

        • 使用 xcodebuild 命令行工具:

          # 安装 CocoaPods 依赖项
          pod install
          
          # 构建项目
          xcodebuild -workspace YourWorkspace.xcworkspace -scheme YourScheme build
        • 使用 Xcode IDE:

          1. 在 Xcode 中打开您的 .xcworkspace 文件。
          2. 选择目标方案(target scheme)。
          3. 选择 Product > Build。您也可以按下 +B
        • fastlane,一个用于自动化 iOS 和 Android 应用构建与发布的工具:

          1. 安装 fastlane

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

            fastlane init
          3. 向您的 Fastfile 添加一个 lane:

            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. 添加私有 spec 仓库:

          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 以安装依赖项并更新工作区。

      记得在更新 Podfile 后始终运行 pod install,以确保所有依赖项正确安装且工作区已更新。

      为漏洞数据库做贡献

      要查找漏洞,您可以搜索 GitLab Advisory Database。 您也可以 提交新的漏洞