通过 CI/CD 变量可以改变 API 模糊测试行为。

API 模糊测试配置文件必须位于您的代码库的 .gitlab 目录中。

{{< alert type=”warning” >}}

所有极狐GitLab 安全扫描工具的自定义应在合并请求中进行测试,然后再合并这些更改到默认分支。未能这样做可能会导致意外结果,包括大量误报。

{{< /alert >}}

身份验证

身份验证通过提供身份验证令牌作为标头或 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

持有者令牌

持有者令牌由几种不同的身份验证机制使用,包括 OAuth2 和 JSON Web Tokens (JWT)。持有者令牌通过 Authorization HTTP 头传输。要与 API 模糊测试一起使用持有者令牌,您需要以下之一:

  • 不会过期的令牌
  • 一种生成持续时间与测试长度相同的令牌的方法
  • 一个可以调用的 Python 脚本来生成令牌的 API 模糊测试

令牌不会过期

如果持有者令牌不会过期,请使用 FUZZAPI_OVERRIDES_ENV 变量来提供它。此变量的内容是一个 JSON 片段,提供要添加到 API 模糊测试的传出 HTTP 请求的标头和 cookie。

按照以下步骤使用 FUZZAPI_OVERRIDES_ENV 提供持有者令牌:

  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 模糊测试并查看模糊测试日志和测试 API 的应用程序日志。有关覆盖命令的更多信息,请参阅 覆盖部分

在测试运行时生成的令牌

如果必须生成持有者令牌并且在测试期间不会过期,则可以提供一个包含令牌的文件给 API 模糊测试。前一个阶段和作业,或部分 API 模糊测试作业,可以生成此文件。

API 模糊测试期望收到一个具有以下结构的 JSON 文件:

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

此文件可以由前一个阶段生成,并通过 FUZZAPI_OVERRIDES_FILE CI/CD 变量提供给 API 模糊测试。

在您的 .极狐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 模糊测试并查看模糊测试日志和测试 API 的应用程序日志。

令牌有短期过期时间

如果必须生成持有者令牌并且在扫描完成之前过期,则可以提供一个程序或脚本供 API 模糊测试器在提供的间隔时间内执行。提供的脚本在安装了 Python 3 和 Bash 的 Alpine Linux 容器中运行。如果 Python 脚本需要其他软件包,它必须检测并在运行时安装这些软件包。

脚本必须以特定格式创建一个包含持有者令牌的 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 模糊测试并查看模糊测试日志和测试 API 的应用程序日志。

API 模糊测试配置文件

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

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

覆盖

API 模糊测试提供了一种方法来添加或覆盖请求中的特定项目,例如:

  • 标头
  • 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 路径 表达式。JSON 路径表达式 $.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。这是一个 群组或实例级别的 CI/CD 变量,在 UI 中定义

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 模糊测试器在指定的间隔时间内执行。提供的脚本在安装了 Python 3 和 Bash 的 Alpine Linux 容器中运行。

您必须将环境变量 FUZZAPI_OVERRIDES_CMD 设置为您希望执行的程序或脚本。提供的命令会根据之前定义的覆盖 JSON 文件生成它。

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

{{< alert type=”note” >}}

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

{{< /alert >}}

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

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

可选:

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

{{< alert type=”warning” >}}

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

{{< /alert >}}

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      : 所有与请求相关的异常
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 文件中指定。要排除多个路径,请使用 ; 字符分隔条目。在提供的路径中,您可以使用单字符通配符 ?* 作为多字符通配符。

要验证路径是否已排除,请查看作业输出中的 Tested OperationsExcluded Operations 部分。您不应在 Tested Operations 下看到任何排除的路径。

2021-05-27 21:51:08 [INF] API Fuzzing: --[ Tested Operations ]-------------------------
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: --[ Excluded Operations ]-----------------------
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 路径表达式。
  • 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 路径排除特定 JSON 节点

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

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

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

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

使用 JSON 路径排除多个 JSON 节点

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

JSON 路径表达式以 $ 开头以指代根节点,并使用 . 指代当前节点。然后使用 users 指代属性,并使用字符 [] 来表示数组中的索引,而不是提供数字作为索引,您可以使用 * 指定任意索引。在索引引用之后,我们发现 . 现在指代数组中任何给定选定索引,后跟属性名称 password

例如,JSON 文档如下所示:

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

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

排除 XML 属性

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

XPath 表达式 /credentials/@isEnabled/ 开头表示 XML 文档的根,然后跟随 credentials 字以指代要匹配的元素名称。它使用一个 / 指代前一个 XML 元素的节点,并使用字符 @ 指代属性名称 isEnabled

例如,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。最后部分有一个 / 指代当前元素,并使用一个 XPath 函数 text() 来标识当前元素的文本。

例如,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 节点

要排除 XML 元素 login,它在命名空间 s 中定义,并包含在根节点 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.yml 中,FUZZAPI_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: --[ Tested Operations ]-------------------------
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: --[ Excluded Operations ]-----------------------
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: ------------------------------------------------

{{< alert type=”note” >}}

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

{{< /alert >}}

示例

排除 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$。在之前的正则表达式中:

  1. . 表示任何字符。
  2. * 表示零次或多次。
  3. $ 表示 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$

标头模糊测试

标头模糊测试默认情况下是禁用的,因为在许多技术栈中会发生大量误报。当启用标头模糊测试时,您必须指定要在模糊测试中包含的标头列表。

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

此代码段显示了 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 是一个布尔值,用于打开和关闭标头模糊测试。默认设置为 false 表示关闭。要打开标头模糊测试,将此设置更改为 true

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

Headers 是要进行模糊测试的标头列表。只有列出的标头会被模糊测试。要对您的 API 使用的标头进行模糊测试,请使用 - Name: HeaderName 语法为其添加条目。例如,要对自定义标头 X-Custom 进行模糊测试,添加 - Name: X-Custom

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

您现在有一个配置来模糊测试标头 X-Custom。使用相同的表示法列出其他标头:

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

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