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

自定义分析器设置

可以通过 CI/CD 变量来改变 API Fuzzing 的行为。

API Fuzzing 配置文件必须位于仓库的 .gitlab 目录中。

所有 GitLab 安全扫描工具的自定义都应在合并请求中进行测试,然后再将这些更改合并到默认分支。否则可能会产生意外结果,包括大量误报。

认证

认证通过提供认证令牌作为标头或 cookie 来处理。您可以提供一个执行认证流程或计算令牌的脚本。

HTTP 基本认证

HTTP 基本认证 是一种内置在 HTTP 协议中的认证方法,与传输层安全 (TLS) 结合使用。

我们建议您创建一个 CI/CD 变量用于密码(例如 TEST_API_PASSWORD),并将其设置为掩码变量。您可以在 GitLab 项目的 设置 > CI/CD 页面的 变量 部分创建 CI/CD 变量。由于掩码变量的限制,您应该在将密码添加为变量之前对其进行 Base64 编码。

最后,在您的 .gitlab-ci.yml 文件中添加两个 CI/CD 变量:

  • FUZZAPI_HTTP_USERNAME: 认证的用户名。
  • FUZZAPI_HTTP_PASSWORD_BASE64: 认证的 Base64 编码密码。
stages:
    - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick-10
  FUZZAPI_HAR: test-api-recording.har
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_HTTP_USERNAME: testuser
  FUZZAPI_HTTP_PASSWORD_BASE64: $TEST_API_PASSWORD

原始密码

如果您不想对密码进行 Base64 编码(或者您使用的是 GitLab 15.3 或更早版本),您可以使用原始密码 FUZZAPI_HTTP_PASSWORD,而不是使用 FUZZAPI_HTTP_PASSWORD_BASE64

Bearer 令牌

Bearer 令牌被多种不同的认证机制使用,包括 OAuth2 和 JSON Web 令牌 (JWT)。Bearer 令牌通过 Authorization HTTP 标头传输。要在 API Fuzzing 中使用 Bearer 令牌,您需要以下之一:

  • 一个不会过期的令牌
  • 一种生成在测试期间有效的令牌的方法
  • 一个 Python 脚本,API Fuzzing 可以调用它来生成令牌

令牌不会过期

如果 Bearer 令牌不会过期,请使用 FUZZAPI_OVERRIDES_ENV 变量来提供它。此变量的内容是一个 JSON 片段,提供要添加到 API Fuzzing 的出站 HTTP 请求中的标头和 cookie。

按照以下步骤使用 FUZZAPI_OVERRIDES_ENV 提供 Bearer 令牌:

  1. 创建一个 CI/CD 变量,例如 TEST_API_BEARERAUTH,值为 {"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}(替换您的令牌)。您可以在 GitLab 项目的 设置 > CI/CD 页面的 变量 部分创建 CI/CD 变量。

  2. 在您的 .gitlab-ci.yml 文件中,将 FUZZAPI_OVERRIDES_ENV 设置为您刚刚创建的变量:

    stages:
      - fuzz
    
    include:
      - template: API-Fuzzing.gitlab-ci.yml
    
    variables:
      FUZZAPI_PROFILE: Quick-10
      FUZZAPI_OPENAPI: test-api-specification.json
      FUZZAPI_TARGET_URL: http://test-deployment/
      FUZZAPI_OVERRIDES_ENV: $TEST_API_BEARERAUTH
  3. 要验证认证是否正常工作,请运行 API Fuzzing 测试并检查 Fuzzing 日志和测试 API 的应用程序日志。有关覆盖命令的更多信息,请参阅覆盖部分

测试时生成令牌

如果必须在测试时生成 Bearer 令牌且不会过期,您可以使用包含令牌的文件提供给 API Fuzzing。之前的阶段和作业,或者 API Fuzzing 作业的一部分,可以生成此文件。

API Fuzzing 期望接收具有以下结构的 JSON 文件:

{
  "headers" : {
    "Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
  }
}

此文件可以由之前的阶段生成,并通过 FUZZAPI_OVERRIDES_FILE CI/CD 变量提供给 API Fuzzing。

在您的 .gitlab-ci.yml 文件中设置 FUZZAPI_OVERRIDES_FILE

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json

要验证认证是否正常工作,请运行 API Fuzzing 测试并检查 Fuzzing 日志和测试 API 的应用程序日志。

令牌具有短过期时间

如果必须在测试期间生成 Bearer 令牌并在扫描完成前过期,您可以提供一个程序或脚本供 API Fuzzer 在指定间隔执行。提供的脚本在安装了 Python 3 和 Bash 的 Alpine Linux 容器中运行。如果 Python 脚本需要额外的包,它必须检测到这一点并在运行时安装这些包。

脚本必须创建一个包含 Bearer 令牌的 JSON 文件,格式如下:

{
  "headers" : {
    "Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
  }
}

您必须提供三个 CI/CD 变量,每个变量都设置为正确的操作:

  • FUZZAPI_OVERRIDES_FILE: 提供的命令生成的 JSON 文件。
  • FUZZAPI_OVERRIDES_CMD: 生成 JSON 文件的命令。
  • FUZZAPI_OVERRIDES_INTERVAL: 运行命令的间隔(以秒为单位)。

例如:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick-10
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
  FUZZAPI_OVERRIDES_CMD: renew_token.py
  FUZZAPI_OVERRIDES_INTERVAL: 300

要验证认证是否正常工作,请运行 API Fuzzing 测试并检查 Fuzzing 日志和测试 API 的应用程序日志。

API Fuzzing 配置文件

GitLab 提供配置文件 gitlab-api-fuzzing-config.yml。它包含几个测试配置文件,每个配置文件执行特定数量的测试。随着测试数量的增加,每个配置文件的运行时间也会增加。

配置文件 模糊测试(每个参数)
Quick-10 10
Medium-20 20
Medium-50 50
Long-100 100

覆盖

API Fuzzing 提供了一种在请求中添加或覆盖特定项目的方法,例如:

  • 标头
  • Cookie
  • 查询字符串
  • 表单数据
  • JSON 节点
  • XML 节点

您可以使用它来注入语义版本标头、认证等。认证部分 包含使用覆盖的示例。

覆盖使用 JSON 文档,其中每种覆盖类型都由一个 JSON 对象表示:

{
  "headers": {
    "header1": "value",
    "header2": "value"
  },
  "cookies": {
    "cookie1": "value",
    "cookie2": "value"
  },
  "query":      {
    "query-string1": "value",
    "query-string2": "value"
  },
  "body-form":  {
    "form-param1": "value",
    "form-param2": "value"
  },
  "body-json":  {
    "json-path1": "value",
    "json-path2": "value"
  },
  "body-xml" :  {
    "xpath1":    "value",
    "xpath2":    "value"
  }
}

设置单个标头的示例:

{
  "headers": {
    "Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
  }
}

同时设置标头和 cookie 的示例:

{
  "headers": {
    "Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
  },
  "cookies": {
    "flags": "677"
  }
}

设置 body-form 覆盖的示例用法:

{
  "body-form":  {
    "username": "john.doe"
  }
}

当请求正文仅包含表单数据内容时,覆盖引擎使用 body-form

设置 body-json 覆盖的示例用法:

{
  "body-json":  {
    "$.credentials.access-token": "iddqd!42.$"
  }
}

对象 body-json 中的每个 JSON 属性名都设置为 JSON Path 表达式。JSON Path 表达式 $.credentials.access-token 标识要用值 iddqd!42.$ 覆盖的节点。当请求正文仅包含 JSON 内容时,覆盖引擎使用 body-json

例如,如果正文设置为以下 JSON:

{
    "credentials" : {
        "username" :"john.doe",
        "access-token" : "non-valid-password"
    }
}

它将被更改为:

{
    "credentials" : {
        "username" :"john.doe",
        "access-token" : "iddqd!42.$"
    }
}

以下是设置 body-xml 覆盖的示例。第一个条目覆盖 XML 属性,第二个条目覆盖 XML 元素:

{
  "body-xml" :  {
    "/credentials/@isEnabled": "true",
    "/credentials/access-token/text()" : "iddqd!42.$"
  }
}

对象 body-xml 中的每个 JSON 属性名都设置为 XPath v2 表达式。XPath 表达式 /credentials/@isEnabled 标识要用值 true 覆盖的属性节点。XPath 表达式 /credentials/access-token/text() 标识要用值 iddqd!42.$ 覆盖的元素节点。当请求正文仅包含 XML 内容时,覆盖引擎使用 body-xml

例如,如果正文设置为以下 XML:

<credentials isEnabled="false">
  <username>john.doe</username>
  <access-token>non-valid-password</access-token>
</credentials>

它将被更改为:

<credentials isEnabled="true">
  <username>john.doe</username>
  <access-token>iddqd!42.$</access-token>
</credentials>

您可以将此 JSON 文档作为文件或环境变量提供。您也可以提供生成 JSON 文档的命令。该命令可以定期运行以支持过期的值。

使用文件

要将覆盖 JSON 作为文件提供,请设置 FUZZAPI_OVERRIDES_FILE CI/CD 变量。路径相对于作业的当前工作目录。

这是一个 .gitlab-ci.yml 示例:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json

使用 CI/CD 变量

要将覆盖 JSON 作为 CI/CD 变量提供,请使用 FUZZAPI_OVERRIDES_ENV 变量。这允许您将 JSON 放置为可以掩码和保护变量。

在此 .gitlab-ci.yml 示例中,FUZZAPI_OVERRIDES_ENV 变量直接设置为 JSON:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_ENV: '{"headers":{"X-API-Version":"2"}}'

在此 .gitlab-ci.yml 示例中,SECRET_OVERRIDES 变量提供 JSON。这是在 UI 中定义的组或实例级别的 CI/CD 变量

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_ENV: $SECRET_OVERRIDES

使用命令

如果必须在过期时生成或重新生成值,您可以提供一个程序或脚本供 API Fuzzer 在指定间隔执行。提供的脚本在安装了 Python 3 和 Bash 的 Alpine Linux 容器中运行。

您必须将环境变量 FUZZAPI_OVERRIDES_CMD 设置为您要执行的程序或脚本。提供的命令会创建如前所述的覆盖 JSON 文件。

您可能想要安装其他脚本运行时,如 NodeJS 或 Ruby,或者您需要为覆盖命令安装依赖项。在这种情况下,您应该将 FUZZAPI_PRE_SCRIPT 设置为提供这些先决条件的脚本文件路径。FUZZAPI_PRE_SCRIPT 提供的脚本在分析器启动之前执行一次。

当执行需要提升权限的操作时,请使用 sudo 命令。 例如,sudo apk add nodejs

有关安装 Alpine Linux 包的信息,请参阅 Alpine Linux 包管理 页面。

您必须提供三个 CI/CD 变量,每个变量都设置为正确的操作:

  • FUZZAPI_OVERRIDES_FILE: 提供的命令生成的文件。
  • FUZZAPI_OVERRIDES_CMD: 负责定期生成覆盖 JSON 文件的覆盖命令。
  • FUZZAPI_OVERRIDES_INTERVAL: 运行命令的间隔(以秒为单位)。

可选:

  • FUZZAPI_PRE_SCRIPT: 在分析器启动之前安装运行时或依赖项的脚本。

要在 Alpine Linux 中执行脚本,您必须首先使用 chmod 命令设置执行权限。例如,要为每个人设置 script.py 的执行权限,请使用命令:sudo chmod a+x script.py。如果需要,您可以将 script.py 版本化,并已设置执行权限。

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
  FUZZAPI_OVERRIDES_CMD: renew_token.py
  FUZZAPI_OVERRIDES_INTERVAL: 300

调试覆盖

默认情况下,覆盖命令的输出是隐藏的。如果覆盖命令返回非零退出代码,该命令将作为作业输出的一部分显示。或者,您可以将变量 FUZZAPI_OVERRIDES_CMD_VERBOSE 设置为任何值,以在生成时显示覆盖命令输出。这在测试覆盖脚本时很有用,但之后应该禁用它,因为它会减慢测试速度。

您还可以将脚本中的消息写入在作业完成或失败时收集的日志文件。日志文件必须创建在特定位置并遵循命名约定。

在覆盖脚本中添加一些基本日志记录很有用,以防脚本在作业正常运行期间意外失败。日志文件会自动作为作业的工件包含,允许您在作业完成后下载它。

按照我们的示例,我们在环境变量 FUZZAPI_OVERRIDES_CMD 中提供了 renew_token.py。请注意脚本中的两件事:

  • 日志文件保存在环境变量 CI_PROJECT_DIR 指示的位置。
  • 日志文件名应匹配 gl-*.log
#!/usr/bin/env python

# 覆盖命令示例

# 覆盖命令可以使用新值更新覆盖 json 文件
# 以供使用。这是更新将在测试期间过期的
# 认证令牌的好方法。

import logging
import json
import os
import requests
import backoff

# [1] 将日志文件保存在环境变量 CI_PROJECT_DIR 指示的目录中
working_directory = os.environ.get( 'CI_PROJECT_DIR')
overrides_file_name = os.environ.get('FUZZAPI_OVERRIDES_FILE', 'api-fuzzing-overrides.json')
overrides_file_path = os.path.join(working_directory, overrides_file_name)

# [2] 文件名应匹配模式:gl-*.log
log_file_path = os.path.join(working_directory, 'gl-user-overrides.log')

# 设置日志记录器
logging.basicConfig(filename=log_file_path, level=logging.DEBUG)

# 使用 `backoff` 装饰器在出现瞬时错误时重试。
@backoff.on_exception(backoff.expo,
                      (requests.exceptions.Timeout,
                       requests.exceptions.ConnectionError),
                       max_time=30)
def get_auth_response():
    authorization_url = 'https://authorization.service/api/get_api_token'
    return requests.get(
        f'{authorization_url}',
        auth=(os.environ.get('AUTH_USER'), os.environ.get('AUTH_PWD'))
    )

# 在我们的示例中,访问令牌是从给定端点获取的
try:

    # 执行 http 请求,响应示例:
    # { "Token" : "abcdefghijklmn" }
    response = get_auth_response()

    # 检查请求是否成功。可能会引发 `requests.exceptions.HTTPError`
    response.raise_for_status()

    # 获取 JSON 数据
    response_body = response.json()

# 如果需要,可以捕获特定的异常
# requests.ConnectionError                  : 发生了网络连接错误问题
# requests.HTTPError                        : HTTP 请求返回不成功状态代码。[Response.raise_for_status()]
# requests.ConnectTimeout                   : 请求在尝试连接到远程服务器时超时
# requests.ReadTimeout                      : 服务器在指定时间内未发送任何数据。
# requests.TooManyRedirects                 : 请求超过了配置的最大重定向次数
# requests.exceptions.RequestException      : 与 Requests 相关的所有异常
except json.JSONDecodeError as json_decode_error:
    # 记录与解码 JSON 响应相关的错误
    logging.error(f'错误,解码 JSON 响令时失败。错误消息: {json_decode_error}')
    raise
except requests.exceptions.RequestException as requests_error:
    # 记录与 `Requests` 相关的异常
    logging.error(f'错误,执行 HTTP 请求时失败。错误消息: {requests_error}')
    raise
except Exception as e:
    # 记录任何其他错误
    logging.error(f'错误,检索访问令牌时发生未知错误。错误消息: {e}')
    raise

# 计算包含覆盖文件内容的对象。
# 它使用从请求获取的数据
overrides_data = {
    "headers": {
        "Authorization": f"Token {response_body['Token']}"
    }
}

# 记录条目,告知文件覆盖计算
logging.info("创建覆盖文件: %s" % overrides_file_path)

# 尝试覆盖文件
try:
    if os.path.exists(overrides_file_path):
        os.unlink(overrides_file_path)

    # 用我们更新的字典覆盖文件
    with open(overrides_file_path, "wb+") as fd:
        fd.write(json.dumps(overrides_data).encode('utf-8'))
except Exception as e:
    # 记录任何其他错误
    logging.error(f'错误,覆盖文件 {overrides_file_path} 时发生未知错误。错误消息: {e}')
    raise

# 记录信息,告知覆盖已成功完成
logging.info("覆盖文件已更新")

# 结束

在覆盖命令示例中,Python 脚本依赖于 backoff 库。为确保在执行 Python 脚本之前安装该库,FUZZAPI_PRE_SCRIPT 设置为安装覆盖命令依赖项的脚本。 例如,以下脚本 user-pre-scan-set-up.sh

#!/bin/bash

# user-pre-scan-set-up.sh
# 确保 python 依赖项已安装

echo "**** 安装 python 依赖项 ****"

sudo pip3 install --no-cache --upgrade --break-system-packages \
    requests \
    backoff

echo "**** python 依赖项已安装 ****"

# 结束

您必须更新配置以将 FUZZAPI_PRE_SCRIPT 设置为新的 user-pre-scan-set-up.sh 脚本。例如:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_PRE_SCRIPT: user-pre-scan-set-up.sh
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
  FUZZAPI_OVERRIDES_CMD: renew_token.py
  FUZZAPI_OVERRIDES_INTERVAL: 300

在之前的示例中,您可以使用脚本 user-pre-scan-set-up.sh 来安装新的运行时或应用程序,稍后您可以在覆盖命令中使用它们。

排除路径

测试 API 时,排除某些路径可能很有用。例如,您可能排除对认证服务或旧版本 API 的测试。要排除路径,请使用 FUZZAPI_EXCLUDE_PATHS CI/CD 变量。此变量在您的 .gitlab-ci.yml 文件中指定。要排除多个路径,请使用 ; 字符分隔条目。在提供的路径中,您可以使用单个字符通配符 ? 和多个字符通配符 *

要验证路径是否被排除,请检查作业输出的 测试操作排除操作 部分。您不应在 测试操作 下看到任何被排除的路径。

2021-05-27 21:51:08 [INF] API Fuzzing: --[ 测试操作 ]-------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: --[ 排除操作 ]-----------------------
2021-05-27 21:51:08 [INF] API Fuzzing: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------

排除路径的示例

此示例排除 /auth 资源。这不排除子资源 (/auth/child)。

variables:
  FUZZAPI_EXCLUDE_PATHS: /auth

要排除 /auth 和子资源 (/auth/child),我们使用通配符。

variables:
  FUZZAPI_EXCLUDE_PATHS: /auth*

要排除多个路径,我们可以使用 ; 字符。在此示例中,我们排除 /auth*/v1/*

variables:
  FUZZAPI_EXCLUDE_PATHS: /auth*;/v1/*

排除参数

测试 API 时,您可能希望排除参数(查询字符串、标头或正文元素)的测试。这可能是因为参数总是导致失败、减慢测试速度或其他原因。要排除参数,您可以使用以下变量之一:FUZZAPI_EXCLUDE_PARAMETER_ENVFUZZAPI_EXCLUDE_PARAMETER_FILE

FUZZAPI_EXCLUDE_PARAMETER_ENV 允许提供包含排除参数的 JSON 字符串。如果 JSON 很短且不经常更改,这是一个不错的选择。另一个选项是变量 FUZZAPI_EXCLUDE_PARAMETER_FILE。此变量设置为文件路径,可以检入仓库、由其他作业作为工件创建,或使用 FUZZAPI_PRE_SCRIPT 从预生成脚本在运行时生成。

使用 JSON 文档排除参数

JSON 文档包含一个 JSON 对象,该对象使用特定属性来标识应排除哪个参数。 您可以在扫描过程中提供以下属性来排除特定参数:

  • headers: 使用此属性排除特定标头。属性的值是要排除的标头名称数组。名称不区分大小写。
  • cookies: 使用此属性的值来排除特定 cookie。属性的值是要排除的 cookie 名称数组。名称区分大小写。
  • query: 使用此属性从查询字符串中排除特定字段。属性的值是要从查询字符串中排除的字段名称数组。名称区分大小写。
  • body-form: 使用此属性从使用媒体类型 application/x-www-form-urlencoded 的请求中排除特定字段。属性的值是要从正文中排除的字段名称数组。名称区分大小写。
  • body-json: 使用此属性从使用媒体类型 application/json 的请求中排除特定 JSON 节点。属性的值是一个数组,数组的每个条目是一个 JSON Path 表达式。
  • body-xml: 使用此属性从使用媒体类型 application/xml 的请求中排除特定 XML 节点。属性的值是一个数组,数组的每个条目是一个 XPath v2 表达式。

以下 JSON 文档是排除参数的预期结构示例。

{
  "headers": [
    "header1",
    "header2"
  ],
  "cookies": [
    "cookie1",
    "cookie2"
  ],
  "query": [
    "query-string1",
    "query-string2"
  ],
  "body-form": [
    "form-param1",
    "form-param2"
  ],
  "body-json": [
    "json-path-expression-1",
    "json-path-expression-2"
  ],
  "body-xml" : [
    "xpath-expression-1",
    "xpath-expression-2"
  ]
}

示例

排除单个标头

要排除标头 Upgrade-Insecure-Requests,将 header 属性的值设置为包含标头名称的数组:[ "Upgrade-Insecure-Requests" ]。例如,JSON 文档如下所示:

{
  "headers": [ "Upgrade-Insecure-Requests" ]
}

标头名称不区分大小写,因此标头名称 UPGRADE-INSECURE-REQUESTS 等同于 Upgrade-Insecure-Requests

要排除标头 Authorization 和 cookie PHPSESSIDcsrftoken,将 headers 属性的值设置为包含标头名称的数组 [ "Authorization" ],将 cookies 属性的值设置为包含 cookie 名称的数组 [ "PHPSESSID", "csrftoken" ]。例如,JSON 文档如下所示:

{
  "headers": [ "Authorization" ],
  "cookies": [ "PHPSESSID", "csrftoken" ]
}

排除 body-form 参数

要排除使用 application/x-www-form-urlencoded 的请求中的 password 字段,将 body-form 属性的值设置为包含字段名称的数组 [ "password" ]。例如,JSON 文档如下所示:

{
  "body-form":  [ "password" ]
}

排除参数在请求使用内容类型 application/x-www-form-urlencoded 时使用 body-form

使用 JSON Path 排除特定 JSON 节点

要排除根对象中的 schema 属性,将 body-json 属性的值设置为包含 JSON Path 表达式的数组 [ "$.schema" ]

JSON Path 表达式使用特殊语法来标识 JSON 节点:$ 指向 JSON 文档的根,. 指向当前对象(在我们的例子中是根对象),文本 schema 指向属性名称。因此,JSON 路径表达式 $.schema 指向根对象中的属性 schema。 例如,JSON 文档如下所示:

{
  "body-json": [ "$.schema" ]
}

排除参数在请求使用内容类型 application/json 时使用 body-jsonbody-json 中的每个条目都预期是一个 JSON Path 表达式。在 JSON Path 中,$*. 等字符具有特殊含义。

使用 JSON Path 排除多个 JSON 节点

要排除根级别 users 数组中每个条目的 password 属性,将 body-json 属性的值设置为包含 JSON Path 表达式的数组 [ "$.users[*].paswword" ]

JSON Path 表达式以 $ 开头以引用根节点,并使用 . 引用当前节点。然后,它使用 users 引用属性,并使用字符 [] 包裹您要使用的数组中的索引,而不是提供数字作为索引,您使用 * 指定任何索引。在索引引用之后,我们找到 .,现在它引用数组中的任何给定选定索引,前面是属性名称 password

例如,JSON 文档如下所示:

{
  "body-json": [ "$.users[*].paswword" ]
}

排除参数在请求使用内容类型 application/json 时使用 body-jsonbody-json 中的每个条目都预期是一个 JSON Path 表达式。在 JSON Path 中,$*. 等字符具有特殊含义。

排除 XML 属性

要排除位于根元素 credentials 中名为 isEnabled 的属性,将 body-xml 属性的值设置为包含 XPath 表达式的数组 [ "/credentials/@isEnabled" ]

XPath 表达式 /credentials/@isEnabled/ 开头,表示 XML 文档的根,然后是单词 credentials,表示要匹配的元素名称。它使用 / 引用前一个 XML 元素的节点,字符 @ 表示名称 isEnable 是一个属性。

例如,JSON 文档如下所示:

{
  "body-xml": [
    "/credentials/@isEnabled"
  ]
}

排除参数在请求使用内容类型 application/xml 时使用 body-xmlbody-xml 中的每个条目都预期是一个 XPath v2 表达式。在 XPath 表达式中,@/:[] 等字符具有特殊含义。

排除 XML 元素的文本

要排除根节点 credentials 中包含的 username 元素的文本,将 body-xml 属性的值设置为包含 XPath 表达式的数组 [/credentials/username/text()" ]

在 XPath 表达式 /credentials/username/text() 中,第一个字符 / 指向根 XML 节点,然后指示一个 XML 元素的名称 credentials。类似地,字符 / 指向当前元素,后跟一个新的 XML 元素的名称 username。最后一部分有一个 / 指向当前元素,并使用一个名为 text() 的 XPath 函数,该函数标识当前元素的文本。

例如,JSON 文档如下所示:

{
  "body-xml": [
    "/credentials/username/text()"
  ]
}

排除参数在请求使用内容类型 application/xml 时使用 body-xmlbody-xml 中的每个条目都预期是一个 XPath v2 表达式。在 XPath 表达式中,@/:[] 等字符具有特殊含义。

排除 XML 元素

要排除根节点 credentials 中包含的 username 元素,将 body-xml 属性的值设置为包含 XPath 表达式的数组 [/credentials/username" ]

在 XPath 表达式 /credentials/username 中,第一个字符 / 指向根 XML 节点,然后指示一个 XML 元素的名称 credentials。类似地,字符 / 指向当前元素,后跟一个新的 XML 元素的名称 username

例如,JSON 文档如下所示:

{
  "body-xml": [
    "/credentials/username"
  ]
}

排除参数在请求使用内容类型 application/xml 时使用 body-xmlbody-xml 中的每个条目都预期是一个 XPath v2 表达式。在 XPath 表达式中,@/:[] 等字符具有特殊含义。

排除带命名空间的 XML 节点

要排除在命名空间 s 中定义的 XML 元素 login,并包含在 credentials 根节点中,将 body-xml 属性的值设置为包含 XPath 表达式的数组 [ "/credentials/s:login" ]

在 XPath 表达式 /credentials/s:login 中,第一个字符 / 指向根 XML 节点,然后指示一个 XML 元素的名称 credentials。类似地,字符 / 指向当前元素,后跟一个新的 XML 元素的名称 s:login。请注意名称包含字符 :,该字符将命名空间与节点名称分开。

命名空间名称应该在作为请求正文一部分的 XML 文档中定义。您可以在规范文档 HAR、OpenAPI 或 Postman Collection 文件中检查命名空间。

{
  "body-xml": [
    "/credentials/s:login"
  ]
}

排除参数在请求使用内容类型 application/xml 时使用 body-xmlbody-xml 中的每个条目都预期是一个 XPath v2 表达式。在 XPath 表达式中,@/:[] 等字符具有特殊含义。

使用 JSON 字符串

要提供排除 JSON 文档,请使用 JSON 字符串设置变量 FUZZAPI_EXCLUDE_PARAMETER_ENV。在以下示例中,.gitlab-ci.ymlFUZZAPI_EXCLUDE_PARAMETER_ENV 变量设置为 JSON 字符串:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_EXCLUDE_PARAMETER_ENV: '{ "headers": [ "Upgrade-Insecure-Requests" ] }'

使用文件

要提供排除 JSON 文档,请使用 JSON 文件路径设置变量 FUZZAPI_EXCLUDE_PARAMETER_FILE。文件路径相对于作业的当前工作目录。在以下 .gitlab-ci.yml 文件中,FUZZAPI_EXCLUDE_PARAMETER_FILE 变量设置为 JSON 文件路径:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_EXCLUDE_PARAMETER_FILE: api-fuzzing-exclude-parameters.json

api-fuzzing-exclude-parameters.json 是一个遵循排除参数文档结构的 JSON 文档。

排除 URL

作为按路径排除的替代方法,您可以使用 FUZZAPI_EXCLUDE_URLS CI/CD 变量按 URL 中的任何其他组件进行过滤。此变量可以在您的 .gitlab-ci.yml 文件中设置。该变量可以存储多个值,用逗号 (,) 分隔。每个值都是一个正则表达式。因为每个条目都是一个正则表达式,所以像 .* 这样的条目会排除所有 URL,因为它是一个匹配所有内容的正则表达式。

在您的作业输出中,您可以检查任何 URL 是否匹配 FUZZAPI_EXCLUDE_URLS 提供的任何正则表达式。匹配的操作列在 排除操作 部分。排除操作 中列出的操作不应列在 测试操作 部分。例如,以下作业输出部分:

2021-05-27 21:51:08 [INF] API Fuzzing: --[ 测试操作 ]-------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: --[ 排除操作 ]-----------------------
2021-05-27 21:51:08 [INF] API Fuzzing: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------

FUZZAPI_EXCLUDE_URLS 中的每个值都是一个正则表达式。字符如 .*$ 等在正则表达式中具有特殊含义。

示例

排除 URL 和子资源

以下示例排除 URL http://target/api/auth 及其子资源。

stages:
  - fuzz

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

variables:
  FUZZAPI_TARGET_URL: http://target/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_EXCLUDE_URLS: http://target/api/auth

排除两个 URL 并允许其子资源

要排除 URL http://target/api/buyhttp://target/api/sell 但允许扫描其子资源,例如:http://target/api/buy/toyhttp://target/api/sell/chair。您可以使用值 http://target/api/buy/$,http://target/api/sell/$。此值使用两个正则表达式,每个用 , 字符分隔。因此,它包含 http://target/api/buy$http://target/api/sell$。在每个正则表达式中,尾随的 $ 字符指出匹配的 URL 应该结束的位置。

stages:
  - fuzz

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

variables:
  FUZZAPI_TARGET_URL: http://target/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_EXCLUDE_URLS: http://target/api/buy/$,http://target/api/sell/$

排除两个 URL 及其子资源

要排除 URL:http://target/api/buyhttp://target/api/sell 及其子资源。要提供多个 URL,我们使用 , 字符,如下所示:

stages:
  - fuzz

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

variables:
  FUZZAPI_TARGET_URL: http://target/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_EXCLUDE_URLS: http://target/api/buy,http://target/api/sell

使用正则表达式排除 URL

要精确排除 https://target/api/v1/user/createhttps://target/api/v2/user/create 或任何其他版本(v3v4 等),我们可以使用 https://target/api/v.*/user/create$。在之前的正则表达式中:

  • . 表示任何字符。
  • * 表示零次或多次。
  • $ 表示 URL 应该在那里结束。
stages:
  - fuzz

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

variables:
  FUZZAPI_TARGET_URL: http://target/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_EXCLUDE_URLS: https://target/api/v.*/user/create$

标头 Fuzzing

由于许多技术栈会产生大量误报,标头 Fuzzing 默认情况下是禁用的。启用标头 Fuzzing 时,您必须指定要在 Fuzzing 中包含的标头列表。

默认配置文件中的每个配置文件都有一个 GeneralFuzzingCheck 条目。此检查执行标头 Fuzzing。在 Configuration 部分,您必须更改 HeaderFuzzingHeaders 设置以启用标头 Fuzzing。

此片段显示了标头 Fuzzing 禁用时的 Quick-10 配置文件的默认配置:

- Name: Quick-10
  DefaultProfile: Empty
  Routes:
  - Route: *Route0
    Checks:
    - Name: FormBodyFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: false
        Headers:
    - Name: JsonFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
    - Name: XmlFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true

HeaderFuzzing 是一个布尔值,用于开启和关闭标头 Fuzzing。默认设置为 false 表示关闭。要开启标头 Fuzzing,请将此设置更改为 true

    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: true
        Headers:

Headers 是要 Fuzzing 的标头列表。只有列出的标头才会被 Fuzzing。要 Fuzzing 您的 API 使用的标头,请使用语法 - Name: HeaderName 添加一个条目。例如,要 Fuzzing 自定义标头 X-Custom,请添加 - Name: X-Custom

    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: true
        Headers:
          - Name: X-Custom

您现在有了 Fuzzing 标头 X-Custom 的配置。使用相同的符号列出其他标头:

    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: true
        Headers:
          - Name: X-Custom
          - Name: X-AnotherHeader

根据需要为每个配置文件重复此配置。