自定义分析器设置
可以通过 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 令牌:
-
创建一个 CI/CD 变量,例如
TEST_API_BEARERAUTH,值为{"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}(替换您的令牌)。您可以在 GitLab 项目的 设置 > CI/CD 页面的 变量 部分创建 CI/CD 变量。 -
在您的
.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 -
要验证认证是否正常工作,请运行 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: 在分析器启动之前安装运行时或依赖项的脚本。
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_ENV 或 FUZZAPI_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。
同时排除一个标头和两个 cookie
要排除标头 Authorization 和 cookie PHPSESSID 和 csrftoken,将 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-json。body-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-json。body-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-xml。body-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-xml。body-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-xml。body-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-xml。body-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.jsonapi-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/buy 和 http://target/api/sell 但允许扫描其子资源,例如:http://target/api/buy/toy 或 http://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/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
要精确排除 https://target/api/v1/user/create 和 https://target/api/v2/user/create 或任何其他版本(v3、v4 等),我们可以使用 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 部分,您必须更改 HeaderFuzzing 和 Headers 设置以启用标头 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: trueHeaderFuzzing 是一个布尔值,用于开启和关闭标头 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根据需要为每个配置文件重复此配置。