自定义分析器设置
可以通过 CI/CD 变量来修改 API 模糊测试的行为。
API 模糊测试的配置文件必须在仓库的 .gitlab
目录下。
认证
认证是通过将身份验证令牌作为标头或 cookie 来处理的。您可以提供执行身份验证流或计算令牌的脚本。
HTTP Basic 认证
HTTP basic 认证是一种内置于 HTTP 写一种的身份验证方法,通常和传输层安全(TLS)一起使用。
我们推荐您为密码创建了一个 CI/CD 变量(比如,TEST_API_PASSWORD
),并将其设置为被屏蔽。您可以通过访问项目的极狐GitLab 页面上的 设置 > CI/CD,在 变量 部分创建 CI/CD 变量。由于屏蔽变量的限制,您应该在添加变量之前对密码进行 Base64 编码。
最后,将两个 CI/CD 变量添加到您的 .gitlab-ci.yml
文件中:
-
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 Tokens(JWT)。Bearer 令牌通过 Authorization
HTTP 标头传输。要在 API 模糊测试中使用 bearer 令牌,您需要以下之一:
- 一个未过期的令牌。
- 生成一个在测试期间持续存在的令牌的方法。
- API 模糊测试可以调用的 Python 脚本来生成令牌。
令牌不过期
如果 bearer 令牌不过期,您可以使用 FUZZAPI_OVERRIDES_ENV
变量来提供它。此变量的内容是一个 JSON 片段,提供要添加到 API 模糊测试的传出 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 模糊测试并查看模糊测试日志和测试 API 的应用程序日志。有关重写命令的更多信息,请参阅重写部分。
在测试运行时生成令牌
如果必须要生成 bearer 令牌而且不能在测试期间过去,您可以为 API 模糊测试提供一个包含令牌的文件。之前的一个 stage 和作业,或作为 API 模糊作业的一部分,可以生成此文件。
API 模糊测试期望接收具有以下结构的 JSON 文件:
{
"headers" : {
"Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}
此文件可以由一个先前的 stage 生成,并通过 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 的应用程序日志。
令牌有短的过期时间
如果必须要生成 bearer 令牌并在扫描完成之前就会过期,那么您可以为 API 模糊测试提供一个程序或脚本,以便在提供的间隔上执行。提供的脚本在 Alpine Linux 容器中运行,该容器安装了 Python 3 和 Bash。如果 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 模糊测试并查看模糊测试日志和测试 API 的应用程序日志。
API 模糊测试资料
极狐GitLab 提供的配置文件 gitlab-api-fuzzing-config.yml
包含几个测试配置文件,执行特定数量的测试。随着测试数量的增加,每个配置文件的运行时间也会增加。
资料 | 模糊测试(每个参数) |
---|---|
Quick-10 | 10 |
Medium-20 | 20 |
Medium-50 | 50 |
Long-100 | 100 |
覆盖
API 模糊测试提供方法在您的请求中添加或覆盖特定的项目,例如:
- Headers
- Cookies
- Query string
- Form data
- JSON nodes
- XML nodes
您可以使用这些项目来注入语义版本标头、身份验证等。身份验证部分包括使用覆盖进行此目的的示例。
覆盖使用 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
对象中的每一个属性名称都设置为一个 XPath 表达式。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 变量
要以 CI/CD 变量的形式提供覆盖的 JSON,使用 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 模糊测试在指定间隔执行。提供的脚本在安装了 Python 3 和 Bash 的 Alpine Linux 容器中运行。
您必须将环境变量 FUZZAPI_OVERRIDES_CMD
设置为要执行的程序或脚本。提供的脚本创建先前定义的覆盖 JSON 文件。
您可能还想要安装其他脚本运行时,如 NodeJS 或 Ruby,或者您可能需要为覆盖命令安装依赖项。在这种情况下,您应该将 FUZZAPI_PRE_SCRIPT
设置为提供这些先决条件的脚本的文件路径。在分析器开始之前,提供的脚本执行一次。
sudo
命令。例如,sudo apk add nodejs
。您必须提供三个环境变量,每个变量都设置为正确的操作:
-
FUZZAPI_OVERRIDES_FILE
: 由提供的命令生成的覆盖 JSON 文件。 -
FUZZAPI_OVERRIDES_CMD
: 负责定期生成覆盖 JSON 文件的覆盖命令。 -
FUZZAPI_OVERRIDES_INTERVAL
: 以秒为单位运行命令的间隔。
可选地:
-
FUZZAPI_PRE_SCRIPT
:在 runner 开始之前安装运行时或依赖项的脚本。
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
# Example of an overrides command
# Override commands can update the overrides json file
# with new values to be used. This is a great way to
# update an authentication token that will expire
# during testing.
import logging
import json
import os
import requests
import backoff
# [1] Store log file in directory indicated by env var 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] File name should match the pattern: gl-*.log
log_file_path = os.path.join(working_directory, 'gl-user-overrides.log')
# Set up logger
logging.basicConfig(filename=log_file_path, level=logging.DEBUG)
# Use `backoff` decorator to retry in case of transient errors.
@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'))
)
# In our example, access token is retrieved from a given endpoint
try:
# Performs a http request, response sample:
# { "Token" : "abcdefghijklmn" }
response = get_auth_response()
# Check that the request is successful. may raise `requests.exceptions.HTTPError`
response.raise_for_status()
# Gets JSON data
response_body = response.json()
# If needed specific exceptions can be caught
# requests.ConnectionError : A network connection error problem occurred
# requests.HTTPError : HTTP request returned an unsuccessful status code. [Response.raise_for_status()]
# requests.ConnectTimeout : The request timed out while trying to connect to the remote server
# requests.ReadTimeout : The server did not send any data in the allotted amount of time.
# requests.TooManyRedirects : The request exceeds the configured number of maximum redirections
# requests.exceptions.RequestException : All exceptions that related to Requests
except json.JSONDecodeError as json_decode_error:
# logs errors related decoding JSON response
logging.error(f'Error, failed while decoding JSON response. Error message: {json_decode_error}')
raise
except requests.exceptions.RequestException as requests_error:
# logs exceptions related to `Requests`
logging.error(f'Error, failed while performing HTTP request. Error message: {requests_error}')
raise
except Exception as e:
# logs any other error
logging.error(f'Error, unknown error while retrieving access token. Error message: {e}')
raise
# computes object that holds overrides file content.
# It uses data fetched from request
overrides_data = {
"headers": {
"Authorization": f"Token {response_body['Token']}"
}
}
# log entry informing about the file override computation
logging.info("Creating overrides file: %s" % overrides_file_path)
# attempts to overwrite the file
try:
if os.path.exists(overrides_file_path):
os.unlink(overrides_file_path)
# overwrites the file with our updated dictionary
with open(overrides_file_path, "wb+") as fd:
fd.write(json.dumps(overrides_data).encode('utf-8'))
except Exception as e:
# logs any other error
logging.error(f'Error, unknown error when overwriting file {overrides_file_path}. Error message: {e}')
raise
# logs informing override has finished successfully
logging.info("Override file has been updated")
# end
在覆盖命令行示例中,Python 脚本依赖于 backoff
库。为了确保在执行 Python 脚本之前安装了库,FUZZAPI_PRE_SCRIPT
被设置为安装覆盖命令的依赖项的脚本。
比如,如下的 user-pre-scan-set-up.sh
脚本:
#!/bin/bash
# user-pre-scan-set-up.sh
# Ensures python dependencies are installed
echo "**** install python dependencies ****"
sudo pip3 install --no-cache --upgrade --break-system-packages \
requests \
backoff
echo "**** python dependencies installed ****"
# end
您不得不更新您的配置来为我们新的 user-pre-scan-set-up.sh
脚本设置 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_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 Operations
和 Excluded 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_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
是一样的。
同时排除标头和两个 cookies
要排除标头 Authorization
和 cookies PHPSESSID
和 csrftoken
,将 headers
属性的值设置为包含标头名称的数组 [ "Authorization" ]
,将 cookies
属性的值设置为包含 cookies 名称的数组 [ "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 路径表达式使用特殊的语法来标识 JSON 节点:$
指的是 JSON 文档的根,.
指的是当前对象(在我们的例子中是根对象),文本 schema
指的是属性名称。因此,JSON 路径表达式 $.schema
指的是根对象中的 schema
属性。例如,JSON 文档如下所示:
{
"body-json": [ "$.schema" ]
}
当请求使用上下文类型 application/json
时,排除参数使用 body-json
。body-json
中的每个条目都应是 JSON Path 表达式。在 JSON Path 中,字符如 $
、*
、.
等具有特殊含义。
使用 JSON 路径排除多个 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
。最后一个部分有一个 /
,它引用当前元素,并使用 XPath 函数 text()
,该函数标识当前元素的文本。
比如,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.json
api-fuzzing-exclude-parameters.json
是遵循排除参数文档结构的 JSON 文档。
排除 URL
作为通过路径排除的替代方法,您可以使用 FUZZAPI_EXCLUDE_URLS
CI/CD 变量按任何其他 URL 组件进行过滤。可以在 .gitlab-ci.yml
文件中设置此变量。该变量可以存储多个值,用逗号(,
)分隔。每个值都是一个正则表达式。因为每个条目都是正则表达式,所以像 .*
这样的条目会排除所有 URL,因为它是一个匹配所有内容的正则表达式。
在您的作业输出中,您可以检查任何提供的正则表达式是否与 FUZZAPI_EXCLUDE_URLS
中的任何 URL 匹配。匹配操作在 排除的操作 部分中列出。在 排除的操作 中列出的操作不应在 测试操作 部分中列出。例如,作业输出的以下部分:
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: ------------------------------------------------
FUZZAPI_EXCLUDE_URLS
中的每个值都是正则表达式。诸如 .
、 *
和 $
等一类的字符在正则表达式中有特殊含义。示例
排除单个 URL 和其子资源
如下示例排除了 http://target/api/auth
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/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$
标头模糊
默认情况下标头模糊是被禁用的,因为许多技术堆栈中出现的大量假阳性。当启用标头模糊时,您必须指定要包含在模糊中的标头列表。
默认配置文件中的每个配置文件都有一个 GeneralFuzzingCheck
条目。此检查执行标头模糊。在 Configuration
部分下,您必须更改 HeaderFuzzing
和 Headers
设置以启用标头模糊。
此代码片段显示了禁用标头模糊的 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
对于每一个需要的配置文件,重复此配置即可。