API Fuzzing 作业在 N 小时后超时

对于较大的代码仓库,API Fuzzing 作业可能会在默认设置的小型 Linux 托管 runner 上超时。如果你的作业中发生这种情况,你应该扩展到更大的 runner。

请参阅以下文档部分以获得帮助:

API Fuzzing 作业完成时间过长

请参阅 性能调优和测试速度

错误:等待 API Fuzzing 'http://127.0.0.1:5000' 可用时出错

在 v1.6.196 之前的 API Fuzzing 分析器版本中存在一个 bug,可能导致后台进程在某些条件下失败。解决方案是更新到较新的 API Fuzzing 分析器版本。

版本信息可以在 apifuzzer_fuzz 作业的作业详情中找到。

如果该议题发生在 v1.6.196 或更高版本,请联系支持并提供以下信息:

  1. 参考此故障排除部分,并要求将议题升级到动态分析团队。
  2. 作业的完整控制台输出。
  3. 作为作业产物提供的 gl-api-security-scanner.log 文件。在作业详情页面的右侧面板中,选择 浏览 按钮。
  4. 从你的 .gitlab-ci.yml 文件中获取 apifuzzer_fuzz 作业定义。

错误消息

  • 在极狐GitLab 15.6 和更高版本中,等待 API Fuzzing 'http://127.0.0.1:5000' 可用时出错
  • 在极狐GitLab 15.5 和更早版本中,等待 API 安全性 'http://127.0.0.1:5000' 可用时出错

无法启动与扫描仪的会话。请重试,如果问题仍然存在,请联系支持。

当 API Fuzzing 引擎无法与扫描仪应用程序组件建立连接时,会输出错误消息。错误消息显示在 apifuzzer_fuzz 作业的作业输出窗口中。此问题的常见原因是后台组件无法使用选定的端口,因为它已被占用。如果时间在其中扮演了角色(竞争条件),则此错误可能间歇性地发生。此问题最常在 Kubernetes 环境中发生,当其他服务映射到容器中导致端口冲突时。

在解决方案之前,确认错误消息是因为端口已被占用而产生的非常重要。要确认这是原因:

  1. 前往作业控制台。

  2. 查找产物 gl-api-security-scanner.log。你可以通过选择 下载 下载所有产物,然后搜索该文件,或者直接通过选择 浏览 开始搜索。

  3. 在文本编辑器中打开文件 gl-api-security-scanner.log

  4. 如果错误消息是因为端口已被占用而产生的,你应该在文件中看到类似以下的消息:

  • 在极狐GitLab 15.5 和更高版本:

    无法绑定到地址 http://127.0.0.1:5500: 地址已被占用。
  • 在极狐GitLab 15.4 和更早版本:

    无法绑定到地址 http://[::]:5000: 地址已被占用。

之前消息中的文本 http://[::]:5000 可能与你的情况不同,例如可能是 http://[::]:5500http://127.0.0.1:5500。只要错误消息的其余部分相同,可以安全地假设端口已被占用。

如果未找到端口已被占用的证据,请检查其他故障排除部分,作业控制台输出中显示相同错误消息。如果没有更多选项,请通过适当的渠道 获取支持或请求改进

一旦确认问题是因为端口已被占用而产生,接下来,极狐GitLab 15.5 和更高版本引入了配置变量 FUZZAPI_API_PORT。此配置变量允许为扫描仪后台组件设置固定的端口号。

解决方案

  1. 确保你的 .gitlab-ci.yml 文件定义了配置变量 FUZZAPI_API_PORT
  2. FUZZAPI_API_PORT 的值更新为大于 1024 的任意可用端口号。我们建议检查新值未被极狐GitLab 使用。请参阅 软件包默认值 中极狐GitLab 使用的端口完整列表。

错误:使用已发布的 OpenAPI 架构验证文档时发现错误

在 API Fuzzing 作业开始时,OpenAPI 规范会根据已发布的架构进行验证。当提供的 OpenAPI 规范有验证错误时,会显示此错误:

错误,OpenAPI 文档无效。
使用已发布的 OpenAPI 架构验证文档时发现错误

在手动创建 OpenAPI 规范时,以及生成架构时,可能会引入错误。

对于自动生成的 OpenAPI 规范,验证错误通常是由于缺少代码注释。

错误消息

  • 错误,OpenAPI 文档无效。使用已发布的 OpenAPI 架构验证文档时发现错误
    • OpenAPI 2.0 架构验证错误 ...
    • OpenAPI 3.0.x 架构验证错误 ...

解决方案

对于生成的 OpenAPI 规范

  1. 识别验证错误。
    1. 使用 Swagger 编辑器在你的规范中识别验证问题。Swagger 编辑器的视觉性质使其更易于理解需要更改的内容。
    2. 或者,你可以查看日志输出并查找架构验证警告。它们以 OpenAPI 2.0 架构验证错误OpenAPI 3.0.x 架构验证错误 消息为前缀。每个失败的验证提供有关 位置描述 的额外信息。JSON 架构验证消息可能很复杂,编辑器可以帮助验证架构文档。
  2. 查看你的框架/技术栈使用的 OpenAPI 生成文档。识别需要进行的更改以生成正确的 OpenAPI 文档。
  3. 验证问题解决后,重新运行你的流水线。

对于手动创建的 OpenAPI 规范

  1. 识别验证错误。
    1. 最简单的解决方案是使用可视化工具编辑和验证 OpenAPI 文档。例如 Swagger 编辑器会突出显示架构错误和可能的解决方案。
    2. 或者,你可以查看日志输出并查找架构验证警告。它们以 OpenAPI 2.0 架构验证错误OpenAPI 3.0.x 架构验证错误 消息为前缀。每个失败的验证提供有关 位置描述 的额外信息。正确处理每个验证失败,然后重新提交 OpenAPI 文档。JSON 架构验证消息可能很复杂,编辑器可以帮助验证架构文档。
  2. 验证问题解决后,重新运行你的流水线。

无法启动扫描器会话(未找到版本标头)

当 API Fuzzing 引擎无法与扫描器应用程序组件建立连接时,会输出错误消息。错误消息显示在 apifuzzer_fuzz 作业的作业输出窗口中。此问题的常见原因是更改了 FUZZAPI_API 变量的默认值。

错误消息

  • 无法启动扫描器会话(未找到版本标头)。

解决方案

  • .gitlab-ci.yml 文件中删除 FUZZAPI_API 变量。该值继承自 API Fuzzing CI/CD 模板。我们推荐这种方法而不是手动设置值。
  • 如果无法删除该变量,请查看最新版本的 API Fuzzing CI/CD 模板 中该值是否已更改。如果是,请更新 .gitlab-ci.yml 文件中的值。

应用程序无法确定目标 API 的基本 URL

当 API Fuzzing 分析器在检查 OpenAPI 文档后无法确定目标 API 时,会输出错误消息。当目标 API 未在 .gitlab-ci.yml 文件中设置时,没有在 environment_url.txt 文件中可用,并且无法使用 OpenAPI 文档计算时,会显示此错误消息。

在检查不同来源时,API Fuzzing 分析器尝试获取目标 API 的优先级顺序。首先,它尝试使用 FUZZAPI_TARGET_URL。如果环境变量未设置,则 API Fuzzing 分析器尝试使用 environment_url.txt 文件。如果没有 environment_url.txt 文件,API Fuzzing 分析器现在使用 OpenAPI 文档内容和在 FUZZAPI_OPENAPI 中提供的 URL(如果提供了 URL)来尝试计算目标 API。

最佳解决方案取决于你的目标 API 是否会在每次部署时发生变化:

静态环境解决方案

此解决方案适用于目标 API URL 不变(静态)的流水线。

添加环境变量

对于目标 API 保持不变的环境,我们建议你通过使用 FUZZAPI_TARGET_URL 环境变量来指定目标 URL。在你的 .gitlab-ci.yml 文件中,添加变量 FUZZAPI_TARGET_URL。该变量必须设置为 API 测试目标的基本 URL。例如:

stages:
  - fuzz

include:
  - template: API-Fuzzing.gitlab-ci.yml

variables:
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OPENAPI: test-api-specification.json

动态环境解决方案

在动态环境中,目标 API 会在每次不同的部署时发生变化。在这种情况下,有多种可能的解决方案,我们建议在处理动态环境时使用 environment_url.txt 文件。

使用 environment_url.txt

为了支持动态环境,其中目标 API URL 在每个流水线期间发生变化,API Fuzzing 支持使用包含要使用的 URL 的 environment_url.txt 文件。此文件不会检入代码仓库中,而是在流水线期间由部署测试目标的作业创建,并作为产物收集,可供流水线中的后续作业使用。创建 environment_url.txt 文件的作业必须在 API Fuzzing 作业之前运行。

  1. 在测试目标部署作业中添加基本 URL 到项目根目录的 environment_url.txt 文件。
  2. 修改测试目标部署作业以收集 environment_url.txt 作为产物。

示例:

deploy-test-target:
  script:
    # 执行部署步骤
    # 创建 environment_url.txt(示例)
    - echo http://${CI_PROJECT_ID}-${CI_ENVIRONMENT_SLUG}.example.org > environment_url.txt

  artifacts:
    paths:
      - environment_url.txt

使用无效架构的 OpenAPI

在某些情况下,文档是自动生成的,具有无效的架构,或者无法及时手动编辑。在这些情况下,API Fuzzing 能够通过设置变量 FUZZAPI_OPENAPI_RELAXED_VALIDATION 执行宽松验证。我们建议提供完全符合 OpenAPI 规范的文档,以防止意外行为。

编辑不符合规范的 OpenAPI 文件

为了检测和纠正不符合 OpenAPI 规范的元素,我们建议使用编辑器。编辑器通常提供文档验证,并建议创建符合架构的 OpenAPI 文档。建议的编辑器包括:

编辑器 OpenAPI 2.0 OpenAPI 3.0.x OpenAPI 3.1.x
Swagger 编辑器 {{< icon name=”check-circle” >}} YAML, JSON {{< icon name=”check-circle” >}} YAML, JSON {{< icon name=”dotted-circle” >}} YAML, JSON
Stoplight Studio {{< icon name=”check-circle” >}} YAML, JSON {{< icon name=”check-circle” >}} YAML, JSON {{< icon name=”check-circle” >}} YAML, JSON

如果你的 OpenAPI 文档是手动生成的,将你的文档加载到编辑器中,并修复任何不符合规范的内容。如果你的文档是自动生成的,将其加载到编辑器中以识别架构中的问题,然后根据你使用的框架进行应用更改。

启用 OpenAPI 宽松验证

宽松验证是针对在 OpenAPI 文档无法满足 OpenAPI 规范的情况下设计的,但它仍然具有足够的内容,可以被不同工具消费。进行验证,但在文档架构方面更不严格。

API Fuzzing 仍然可以尝试消费不完全符合 OpenAPI 规范的 OpenAPI 文档。为了指示 API Fuzzing 分析器执行宽松验证,请将变量 FUZZAPI_OPENAPI_RELAXED_VALIDATION 设置为任意值,例如:

stages:
  - fuzz

include:
  - template: API-Fuzzing.gitlab-ci.yml

variables:
  FUZZAPI_PROFILE: Quick-10
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_OPENAPI_RELAXED_VALIDATION: 'On'

OpenAPI 文档中的操作未使用任何支持的媒体类型

API Fuzzing 使用 OpenAPI 文档中指定的媒体类型生成请求。如果由于缺少支持的媒体类型而无法创建请求,则会抛出错误。

错误消息

  • 错误,OpenAPI 文档中的操作未使用任何支持的媒体类型。检查 'OpenAPI 规范' 以查看支持的媒体类型。

解决方案

  1. 查看 OpenAPI 规范 部分中的支持媒体类型。
  2. 编辑你的 OpenAPI 文档,允许至少一个给定操作接受任何支持的媒体类型。或者,可以在 OpenAPI 文档级别设置支持的媒体类型,并应用于所有操作。此步骤可能需要更改你的应用程序,以确保支持的媒体类型被应用程序接受。

错误:无法建立 SSL 连接,请参阅内部异常。

API Fuzzing 兼容广泛的 TLS 配置,包括过时的协议和密码。尽管具有广泛的支持,你可能会遇到连接错误,例如:

错误,尝试下载 `<URL>` 时发生错误:
从 Uri:' <URL>' 检索内容时出错。
错误:无法建立 SSL 连接,请参阅内部异常。

此错误发生的原因是 API Fuzzing 无法在给定 URL 与服务器建立安全连接。

要解决该问题:

如果错误消息中的主机支持非 TLS 连接,请在你的配置中将 https:// 更改为 http://。例如,如果在以下配置中发生错误:

stages:
  - fuzz

include:
  - template: API-Fuzzing.gitlab-ci.yml

variables:
  FUZZAPI_TARGET_URL: https://test-deployment/
  FUZZAPI_OPENAPI: https://specs/openapi.json

FUZZAPI_OPENAPI 的前缀从 https:// 更改为 http://

stages:
  - fuzz

include:
  - template: API-Fuzzing.gitlab-ci.yml

variables:
  FUZZAPI_TARGET_URL: https://test-deployment/
  FUZZAPI_OPENAPI: http://specs/openapi.json

如果你无法使用非 TLS 连接访问该 URL,请联系支持团队寻求帮助。

你可以使用 testssl.sh 工具 加快调查。从具有 bash shell 和连接到受影响服务器的机器上:

  1. https://github.com/drwetter/testssl.sh/releases 下载最新发布的 ziptar.gz 文件并解压缩。
  2. 运行 ./testssl.sh --log https://specs
  3. 将日志文件附加到你的支持票证。

错误:作业失败:拉取镜像失败

当从需要身份验证才能访问的容器注册表(它不是公开的)拉取镜像时,会发生此错误消息。

在作业控制台输出中,错误看起来像:

Running with gitlab-runner 15.6.0~beta.186.ga889181a (a889181a)
  on blue-2.shared.runners-manager.gitlab.com/default XxUrkriX
Resolving secrets
00:00
Preparing the "docker+machine" executor
00:06
Using Docker executor with image registry.gitlab.com/security-products/api-security:2 ...
Starting service registry.example.com/my-target-app:latest ...
Pulling docker image registry.example.com/my-target-app:latest ...
WARNING: Failed to pull image with policy "always": Error response from daemon: Get https://registry.example.com/my-target-app/manifests/latest: unauthorized (manager.go:237:0s)
ERROR: Job failed: failed to pull image "registry.example.com/my-target-app:latest" with specified policies [always]: Error response from daemon: Get https://registry.example.com/my-target-app/manifests/latest: unauthorized (manager.go:237:0s)

错误消息

  • 在极狐GitLab 15.9 及更早版本中,错误:作业失败:拉取镜像失败 后跟 来自 daemon 的错误响应:获取镜像:未授权

解决方案

身份验证凭据通过 从私有容器注册表访问镜像 文档部分中概述的方法提供。使用的方法由你的容器注册表提供者及其配置决定。如果你使用第三方提供的容器注册表,例如云提供商(Azure、Google Could (GCP)、AWS 等),请查看提供商文档以获取有关如何对其容器注册表进行身份验证的信息。

以下示例使用 静态定义的凭据 身份验证方法。在此示例中,容器注册表为 registry.example.com,镜像为 my-target-app:latest

  1. 阅读 确定你的 DOCKER_AUTH_CONFIG 数据,以了解如何计算 DOCKER_AUTH_CONFIG 的变量值。配置变量 DOCKER_AUTH_CONFIG 包含 Docker JSON 配置,以提供适当的身份验证信息。例如,要访问私有容器注册表:registry.example.com,使用凭据 abcdefghijklmn,Docker JSON 如下:

    {
        "auths": {
            "registry.example.com": {
                "auth": "abcdefghijklmn"
            }
        }
    }
    
  2. DOCKER_AUTH_CONFIG 添加为 CI/CD 变量。不要直接在你的 .gitlab-ci.yml 文件中添加配置变量,而是应该创建项目 CI/CD 变量
  3. 重新运行你的作业,现在使用静态定义的凭据登录到私有容器注册表 registry.example.com,并让你拉取镜像 my-target-app:latest。如果成功,作业控制台显示类似的输出:

    Running with gitlab-runner 15.6.0~beta.186.ga889181a (a889181a)
      on blue-4.shared.runners-manager.gitlab.com/default J2nyww-s
    Resolving secrets
    00:00
    Preparing the "docker+machine" executor
    00:56
    Using Docker executor with image registry.gitlab.com/security-products/api-security:2 ...
    Starting service registry.example.com/my-target-app:latest ...
    Authenticating with credentials from $DOCKER_AUTH_CONFIG
    Pulling docker image registry.example.com/my-target-app:latest ...
    Using docker image sha256:139c39668e5e4417f7d0eb0eeb74145ba862f4f3c24f7c6594ecb2f82dc4ad06 for registry.example.com/my-target-app:latest with digest registry.example.com/my-target-
    app@sha256:2b69fc7c3627dbd0ebaa17674c264fcd2f2ba21ed9552a472acf8b065d39039c ...
    Waiting for services to be up and running (timeout 30 seconds)...

sudo:设置了 "无新权限" 标志,阻止 sudo 以 root 身份运行。

从分析器的 v5 版本开始,默认情况下使用非 root 用户。这需要在执行特权操作时使用 sudo

此错误发生在特定的容器 daemon 设置中,阻止运行的容器获得新权限。在大多数设置中,这不是默认配置,它是专门配置的,通常是作为安全加固指南的一部分。

错误消息

此问题可以通过在执行 before_scriptFUZZAPI_PRE_SCRIPT 时生成的错误消息进行识别:

$ sudo apk add nodejs

sudo:设置了 "无新权限" 标志,阻止 sudo 以 root 身份运行。

sudo:如果 sudo 在容器中运行,你可能需要调整容器配置以禁用该标志。

解决方案

此问题可以通过以下方式解决:

  • root 用户身份运行容器。建议测试此配置,因为它可能无法在所有情况下工作。这可以通过修改 CICD 配置并检查作业输出以确保 whoami 返回 root 而不是 gitlab 来完成。如果显示 gitlab,请使用其他解决方案。测试完成后可以删除 before_script

    apifuzzer_fuzz:
      image:
        name: $SECURE_ANALYZERS_PREFIX/$FUZZAPI_IMAGE:$FUZZAPI_VERSION$FUZZAPI_IMAGE_SUFFIX
        docker:
          user: root
     before_script:
       - whoami
    

    示例作业控制台输出:

    Executing "step_script" stage of the job script
    Using docker image sha256:8b95f188b37d6b342dc740f68557771bb214fe520a5dc78a88c7a9cc6a0f9901 for registry.gitlab.com/security-products/api-security:5 with digest registry.gitlab.com/security-products/api-security@sha256:092909baa2b41db8a7e3584f91b982174772abdfe8ceafc97cf567c3de3179d1 ...
    $ whoami
    root
    $ /peach/analyzer-api-fuzzing
    17:17:14 [INF] API Security: 极狐GitLab API Security
    17:17:14 [INF] API Security: -------------------
    17:17:14 [INF] API Security:
    17:17:14 [INF] API Security: version: 5.7.0
  • 封装容器并在构建时添加任何依赖项。此选项的好处是以低于 root 的权限运行,这可能是某些客户的要求。

    1. 创建一个新的 Dockerfile 来封装现有镜像。

      ARG SECURE_ANALYZERS_PREFIX
      ARG FUZZAPI_IMAGE
      ARG FUZZAPI_VERSION
      ARG FUZZAPI_IMAGE_SUFFIX
      FROM $SECURE_ANALYZERS_PREFIX/$FUZZAPI_IMAGE:$FUZZAPI_VERSION$FUZZAPI_IMAGE_SUFFIX
      USER root
      
      RUN pip install ...
      RUN apk add ...
      
      USER gitlab
      
    2. 在 API Fuzzing 作业开始之前构建新镜像并将其推送到本地容器注册表。作业完成后应删除镜像。

      TARGET_NAME=apifuzz-$CI_COMMIT_SHA
      docker build -t $TARGET_IMAGE \
        --build-arg "SECURE_ANALYZERS_PREFIX=$SECURE_ANALYZERS_PREFIX" \
        --build-arg "FUZZAPI_IMAGE=$APISEC_IMAGE" \
        --build-arg "FUZZAPI_VERSION=$APISEC_VERSION" \
        --build-arg "FUZZAPI_IMAGE_SUFFIX=$APISEC_IMAGE_SUFFIX" \
        .
      docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
      docker push $TARGET_IMAGE
      
    3. 扩展 apifuzzer_fuzz 作业并使用新镜像名称。

      apifuzzer_fuzz:
        image: apifuzz-$CI_COMMIT_SHA
      
    4. 从注册表中删除临时容器。有关删除容器镜像的信息,请参阅 此文档页面。

  • 更改极狐GitLab Runner 配置,禁用无新权限标志。这可能会产生安全影响,应与你的运营和安全团队讨论。

索引超出数组边界。 在 Peach.Web.Runner.Services.RunnerOptions.GetHeaders()

此错误消息表明 API Fuzzing 分析器无法解析 FUZZAPI_REQUEST_HEADERSFUZZAPI_REQUEST_HEADERS_BASE64 配置变量的值。

错误消息

此问题可以通过两个错误消息来识别。第一个错误消息出现在作业控制台输出中,第二个出现在 gl-api-security-scanner.log 文件中。

作业控制台的错误消息:

05:48:38 [ERR] API Security: 测试失败:发生了意外异常:索引超出数组边界。

gl_api_security-scanner.log 的错误消息:

08:45:43.616 [ERR] <Peach.Web.Core.Services.WebRunnerMachine> WebRunnerMachine::Run() 中出现意外异常
System.IndexOutOfRangeException: 索引超出数组边界。
   在 Peach.Web.Runner.Services.RunnerOptions.GetHeaders() 中 /builds/gitlab-org/security-products/analyzers/api-fuzzing-src/web/PeachWeb/Runner/Services/[RunnerOptions.cs:line 362
   在 Peach.Web.Runner.Services.RunnerService.Start(Job job, IRunnerOptions options) 中 /builds/gitlab-org/security-products/analyzers/api-fuzzing-src/web/PeachWeb/Runner/Services/RunnerService.cs:line 67
   在 Peach.Web.Core.Services.WebRunnerMachine.Run(IRunnerOptions runnerOptions, CancellationToken token) 中 /builds/gitlab-org/security-products/analyzers/api-fuzzing-src/web/PeachWeb/Core/Services/WebRunnerMachine.cs:line 321
08:45:43.634 [WRN] <Peach.Web.Core.Services.WebRunnerMachine> * 会话失败:发生了意外异常:索引超出数组边界。
08:45:43.677 [INF] <Peach.Web.Core.Services.WebRunnerMachine> 测试完成。执行了总计 0 次请求。

解决方案

此问题是由于格式错误的 FUZZAPI_REQUEST_HEADERSFUZZAPI_REQUEST_HEADERS_BASE64 变量引起的。预期格式是一个或多个 Header: value 构造的标头,以逗号分隔。解决方案是纠正语法以符合预期。

有效示例:

  • Authorization: Bearer XYZ
  • X-Custom: Value,Authorization: Bearer XYZ

无效示例:

  • Header:,value
  • HeaderA: value,HeaderB:,HeaderC: value
  • Header