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

API 安全测试作业故障排除

API 安全测试作业在 N 小时后超时

对于较大的仓库,API 安全测试作业可能会在 Linux 上的小型托管运行器上超时,这是默认设置。如果您的作业出现这种情况,应该升级到更大的运行器

请参考以下文档章节获取帮助:

API 安全测试作业完成时间过长

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

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

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

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

如果问题出现在 v1.6.196 或更高版本中,请联系支持团队并提供以下信息:

  1. 引用本故障排除章节,并请求将问题升级到动态分析团队。
  2. 作业的完整控制台输出。
  3. 作为作业工件的 gl-api-security-scanner.log 文件。在作业详情页面的右侧面板中,选择 Browse 按钮。
  4. .gitlab-ci.yml 文件中的 dast_api 作业定义。

错误消息

  • GitLab 15.6 及更高版本中,等待 DAST API 'http://127.0.0.1:5000' 可用时出错
  • 在 GitLab 15.5 及更早版本中,等待 API Security 'http://127.0.0.1:5000' 可用时出错

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

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

错误消息

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

解决方案

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

无法启动与扫描器的会话。请重试,如果问题持续,请联系支持。

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

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

  1. 转到作业控制台。

  2. 查找工件 gl-api-security-scanner.log。您可以通过选择 Download 下载所有工件然后搜索文件,或者直接选择 Browse 开始搜索。

  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 及更高版本引入了配置变量 APISEC_API_PORT。此配置变量允许为扫描器后台组件设置固定端口号。

解决方案

  1. 确保您的 .gitlab-ci.yml 文件定义了配置变量 APISEC_API_PORT
  2. APISEC_API_PORT 的值更新为任何大于 1024 的可用端口号。我们建议检查新值是否未被 GitLab 使用。有关 GitLab 使用的端口完整列表,请参阅包默认值

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

当 API 安全测试引擎在检查 OpenAPI 文档后无法确定目标 API 时,会输出错误消息。当目标 API 未在 .gitlab-ci.yml 文件中设置、在 environment_url.txt 文件中不可用,并且无法使用 OpenAPI 文档计算时,会显示此错误消息。

API 安全测试引擎在检查不同来源时尝试获取目标 API 时有一个优先顺序。首先,它尝试使用 APISEC_TARGET_URL。如果未设置环境变量,则 API 安全测试引擎尝试使用 environment_url.txt 文件。如果没有 environment_url.txt 文件,则 API 安全测试引擎使用 OpenAPI 文档内容和 APISEC_OPENAPI 中提供的 URL(如果提供了 URL)来尝试计算目标 API。

最适合的解决方案取决于您的目标 API 是否每次部署都会更改。在静态环境中,目标 API 每次部署都相同,在这种情况下,请参考静态环境解决方案。如果目标 API 每次部署都会更改,则应应用动态环境解决方案

API 安全测试作业从操作中排除某些路径

如果您发现某些路径被排除在操作之外,请确保:

  • 变量 DAST_API_EXCLUDE_URLS 未配置为排除您想要测试的操作。

  • 目标定义 JSON 文件中定义了 consumes 数组并且具有有效类型。

    有关示例定义,请参阅示例项目目标定义文件

静态环境解决方案

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

添加环境变量

对于目标 API 保持不变的环境,我们建议您使用 APISEC_TARGET_URL 环境变量指定目标 URL。在您的 .gitlab-ci.yml 中,添加一个变量 APISEC_TARGET_URL。该变量必须设置为 API 测试目标的基础 URL。例如:

stages:
  - dast

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

variables:
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_OPENAPI: test-api-specification.json

动态环境解决方案

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

使用 environment_url.txt

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

  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 安全测试可以通过设置变量 APISEC_OPENAPI_RELAXED_VALIDATION 执行宽松验证。我们建议提供完全符合规范的 OpenAPI 文档,以防止意外行为。

编辑不符合规范的 OpenAPI 文件

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

编辑器 OpenAPI 2.0 OpenAPI 3.0.x OpenAPI 3.1.x
Stoplight Studio check-circle YAML, JSON check-circle YAML, JSON check-circle YAML, JSON
Swagger Editor check-circle YAML, JSON check-circle YAML, JSON dotted-circle YAML, JSON

如果您的 OpenAPI 文档是手动生成的,请在编辑器中加载文档并修复任何不符合规范的元素。如果您的文档是自动生成的,请在编辑器中加载它以识别架构中的问题,然后转到应用程序并根据您使用的框架进行更正。

启用 OpenAPI 宽松验证

宽松验证适用于 OpenAPI 文档无法满足 OpenAPI 规范但仍具有足够内容供不同工具使用的情况。执行验证,但在文档架构方面不那么严格。

API 安全测试仍然可以尝试使用不完全符合 OpenAPI 规范的 OpenAPI 文档。要指示 API 安全测试执行宽松验证,将变量 APISEC_OPENAPI_RELAXED_VALIDATION 设置为任何值,例如:

stages:
  - dast

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

variables:
  APISEC_PROFILE: Quick
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_OPENAPI: test-api-specification.json
  APISEC_OPENAPI_RELAXED_VALIDATION: 'On'

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

API 安全测试使用 OpenAPI 文档中指定的媒体类型生成请求。如果没有支持的媒体类型无法创建请求,则会抛出错误。

错误消息

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

解决方案

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

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

API 安全测试兼容广泛的 TLS 配置,包括过时的协议和密码。 尽管支持广泛,您可能会遇到连接错误,如下所示:

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

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

要解决此问题:

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

stages:
  - dast

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

variables:
  APISEC_TARGET_URL: https://test-deployment/
  APISEC_OPENAPI: https://specs/openapi.json

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

stages:
  - dast

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

variables:
  APISEC_TARGET_URL: https://test-deployment/
  APISEC_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. 将日志文件附加到您的支持工单中。

ERROR: Job failed: failed to pull image

当从需要身份验证才能访问(非公开)的容器注册表中拉取镜像时,会出现此错误消息。

在作业控制台输出中,错误如下所示:

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 及更早版本中,ERROR: Job failed: failed to pull image 后跟 Error response from daemon: Get IMAGE: unauthorized

解决方案

身份验证凭证使用 从私有容器注册表访问镜像 文档部分中概述的方法提供。使用的方法取决于您的容器注册表提供者及其配置。如果您使用的是第三方提供的容器注册表,例如云提供商(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)...

连续扫描之间的漏洞结果不同

在没有代码或配置更改的情况下,连续扫描可能会返回不同的漏洞发现。这主要是由于目标环境及其状态的不确定性,以及扫描器发送的请求的并行化。扫描器并行发送多个请求以优化扫描时间,这意味着目标服务器响应请求的确切顺序是预先确定的。

如果服务器负载过载且无法在给定阈值内响应对测试的请求,可能会检测到基于请求和响应之间时间长度的时序攻击漏洞,例如操作系统命令或 SQL 注入。当服务器未负载过载时,相同的扫描执行可能不会返回这些漏洞的积极发现,从而导致结果不同。分析目标服务器,性能调优和测试速度,以及在测试期间建立最佳服务器性能的基线,可能有助于识别由于上述因素可能出现误报的位置。

sudo: 设置了"no new privileges"标志,这阻止了 sudo 以 root 身份运行。

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

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

错误消息

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

$ sudo apk add nodejs

sudo: 设置了"no new privileges"标志,这阻止了 sudo 以 root 身份运行。

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

解决方案

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

  • root 用户运行容器。您应该测试此配置,因为它可能不适用于所有情况。这可以通过修改 CI/CD 配置并检查作业输出来确保 whoami 返回 root 而不是 gitlab 来完成。如果显示 gitlab,请使用其他解决方法。测试确认更改成功后,可以删除 before_script

    api_security:
      image:
        name: $SECURE_ANALYZERS_PREFIX/$APISEC_IMAGE:$APISEC_VERSION$APISEC_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-security
    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 APISEC_IMAGE
      ARG APISEC_VERSION
      ARG APISEC_IMAGE_SUFFIX
      FROM $SECURE_ANALYZERS_PREFIX/$APISEC_IMAGE:$APISEC_VERSION$APISEC_IMAGE_SUFFIX
      USER root
      
      RUN pip install ...
      RUN apk add ...
      
      USER gitlab
    2. 在 API 安全测试作业开始之前,构建新镜像并将其推送到您的本地容器注册表。应在 api_security 作业完成后删除该镜像。

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

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

  • 更改 GitLab Runner 配置,禁用 no-new-privileges 标志。这可能会带来安全影响,应与您的运维和安全团队讨论。

Index was outside the bounds of the array. at Peach.Web.Runner.Services.RunnerOptions.GetHeaders()

此错误消息表明 API 安全测试分析器无法解析 APISEC_REQUEST_HEADERSAPISEC_REQUEST_HEADERS_BASE64 配置变量的值。

错误消息

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

来自作业控制台的错误消息:

05:48:38 [ERR] API Security: Testing failed: An unexpected exception occurred: Index was outside the bounds of the array.

来自 gl_api_security-scanner.log 的错误消息:

08:45:43.616 [ERR] <Peach.Web.Core.Services.WebRunnerMachine> Unexpected exception in WebRunnerMachine::Run()
System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Peach.Web.Runner.Services.RunnerOptions.GetHeaders() in /builds/gitlab-org/security-products/analyzers/api-fuzzing-src/web/PeachWeb/Runner/Services/[RunnerOptions.cs:line 362
   at Peach.Web.Runner.Services.RunnerService.Start(Job job, IRunnerOptions options) in /builds/gitlab-org/security-products/analyzers/api-fuzzing-src/web/PeachWeb/Runner/Services/RunnerService.cs:line 67
   at Peach.Web.Core.Services.WebRunnerMachine.Run(IRunnerOptions runnerOptions, CancellationToken token) in /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> * Session failed: An unexpected exception occurred: Index was outside the bounds of the array.
08:45:43.677 [INF] <Peach.Web.Core.Services.WebRunnerMachine> Finished testing. Performed a total of 0 requests.

解决方案

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

有效示例:

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

无效示例:

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