自定义分析器设置
认证
认证通过提供认证令牌作为头信息或 Cookie 来处理。你可以提供一个执行认证流程或计算令牌的脚本。
HTTP 基本认证
HTTP 基本认证 是一种内置于 HTTP 协议的认证方法,与 传输层安全(TLS) 结合使用。
我们建议你 创建一个 CI/CD 变量 用于密码(例如,TEST_API_PASSWORD),并将其设置为掩码。你可以在 GitLab 项目的页面中,通过 设置 > CI/CD,在 变量 部分创建 CI/CD 变量。由于 掩码变量的限制,你应该在添加变量前对密码进行 Base64 编码。
最后,在你的 .gitlab-ci.yml 文件中添加两个 CI/CD 变量:
APISEC_HTTP_USERNAME:认证的用户名。APISEC_HTTP_PASSWORD_BASE64:认证用的 Base64 编码密码。
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_HAR: test-api-recording.har
APISEC_TARGET_URL: http://test-deployment/
APISEC_HTTP_USERNAME: testuser
APISEC_HTTP_PASSWORD_BASE64: $TEST_API_PASSWORD原始密码
如果你不想对密码进行 Base64 编码(或者你使用的是 GitLab 15.3 或更早版本),你可以提供原始密码 APISEC_HTTP_PASSWORD,而不是使用 APISEC_HTTP_PASSWORD_BASE64。
令牌(Bearer tokens)
令牌(Bearer tokens)被多种不同的认证机制使用,包括 OAuth2 和 JSON Web Tokens(JWT)。令牌通过 Authorization HTTP 头传输。要在 API 安全测试中使用令牌,你需要以下之一:
- 一个不会过期的令牌。
- 一种能生成持续整个测试长度的令牌的方法。
- 一个 Python 脚本,API 安全测试可以调用它来生成令牌。
令牌不过期
如果令牌不过期,使用 APISEC_OVERRIDES_ENV 变量提供它。该变量的内容是一个 JSON 片段,提供了要添加到 API 安全测试发出的 HTTP 请求中的头信息和 Cookie。
按照以下步骤使用 APISEC_OVERRIDES_ENV 提供令牌:
-
创建一个 CI/CD 变量,例如
TEST_API_BEARERAUTH,值为{"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}(替换你的令牌)。你可以在 GitLab 项目页面中,通过 设置 > CI/CD,在 变量 部分创建 CI/CD 变量。 由于TEST_API_BEARERAUTH的格式,无法对该变量进行掩码。要掩码令牌值,你可以创建第二个包含令牌值的变量,并将TEST_API_BEARERAUTH定义为{"headers":{"Authorization":"Bearer $MASKED_VARIABLE"}}。 -
在你的
.gitlab-ci.yml文件中,将APISEC_OVERRIDES_ENV设置为刚创建的变量:stages: - dast include: - template: API-Security.gitlab-ci.yml variables: APISEC_PROFILE: Quick APISEC_OPENAPI: test-api-specification.json APISEC_TARGET_URL: http://test-deployment/ APISEC_OVERRIDES_ENV: $TEST_API_BEARERAUTH -
要验证认证是否有效,运行 API 安全测试并查看作业日志和测试 API 的应用程序日志。
测试运行时生成的令牌
如果令牌必须在测试期间生成且不会过期,你可以向 API 安全测试提供一个包含令牌的文件。之前的阶段和作业,或 API 安全测试作业的一部分,可以生成此文件。
API 安全测试期望收到具有以下结构的 JSON 文件:
{
"headers" : {
"Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}这个文件可以由之前的阶段生成,并通过 APISEC_OVERRIDES_FILE CI/CD 变量提供给 API 安全测试。
在你的 .gitlab-ci.yml 文件中设置 APISEC_OVERRIDES_FILE:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_OVERRIDES_FILE: dast-api-overrides.json要验证认证是否有效,运行 API 安全测试并查看作业日志和测试 API 的应用程序日志。
Token 过期时间较短
如果Bearer token必须在扫描完成前生成并过期,你可以提供一个程序或脚本来让API安全测试扫描器在指定的时间间隔内执行。提供的脚本在一个安装了Python 3和Bash的Alpine Linux容器中运行。如果Python脚本需要额外的包,它必须检测到这一点并在运行时安装这些包。
脚本必须创建一个包含Bearer token的JSON文件,格式如下:
{
"headers" : {
"Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}你必须提供三个CI/CD变量,每个都设置为正确的操作值:
APISEC_OVERRIDES_FILE:提供的命令生成的JSON文件。APISEC_OVERRIDES_CMD:生成JSON文件的命令。APISEC_OVERRIDES_INTERVAL:运行命令的时间间隔(秒)。
例如:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_OVERRIDES_FILE: dast-api-overrides.json
APISEC_OVERRIDES_CMD: renew_token.py
APISEC_OVERRIDES_INTERVAL: 300要验证认证是否正常工作,运行API安全测试并查看作业日志和测试API的应用日志。有关覆盖命令的更多信息,请参阅[覆盖项部分]。
覆盖项
API安全测试提供了一种方法来添加或覆盖请求中的特定项目,例如:
- Headers
- Cookies
- 查询字符串
- 表单数据
- 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"
}
}设置单个Header的示例:
{
"headers": {
"Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}同时设置Header和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作为文件提供,需设置 APISEC_OVERRIDES_FILE CI/CD 变量。路径相对于作业当前工作目录。
以下是一个示例 .gitlab-ci.yml:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_OVERRIDES_FILE: dast-api-overrides.json使用CI/CD变量
要将覆盖的JSON作为CI/CD变量提供,请使用 APISEC_OVERRIDES_ENV 变量。
这允许你将JSON放置在可被屏蔽和保护的变量中。
在此示例 .gitlab-ci.yml 中,APISEC_OVERRIDES_ENV 变量直接设置为JSON:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_OVERRIDES_ENV: '{"headers":{"X-API-Version":"2"}}'在此示例 .gitlab-ci.yml 中,SECRET_OVERRIDES 变量提供了JSON。这是一个
在UI中定义的群组或实例CI/CD变量:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_OVERRIDES_ENV: $SECRET_OVERRIDES使用命令
若值需要在到期时生成或重新生成,你可以提供一个程序或脚本供
API安全测试扫描器在指定间隔执行。提供的命令在已安装Python 3和Bash的Alpine Linux容器中运行。
你必须将环境变量 APISEC_OVERRIDES_CMD 设置为要执行的程序或脚本。提供的命令会创建之前定义的覆盖JSON文件。
你可能想安装其他脚本运行时(如NodeJS或Ruby),或需要为覆盖命令安装依赖项。此时应将 APISEC_PRE_SCRIPT 设为提供这些先决条件的脚本的文件路径。由 APISEC_PRE_SCRIPT 提供的脚本会在分析器启动前执行一次。
当执行需要提升权限的操作时,请使用 sudo 命令。
例如,sudo apk add nodejs。
有关安装Alpine Linux软件包的信息,请参阅 Alpine Linux软件包管理 页面。
你必须提供三个CI/CD变量,每个都需正确设置以确保正常运行:
APISEC_OVERRIDES_FILE:由提供的命令生成的文件。APISEC_OVERRIDES_CMD:负责定期生成覆盖JSON文件的命令。APISEC_OVERRIDES_INTERVAL:运行命令的时间间隔(秒)。
可选:
APISEC_PRE_SCRIPT:在扫描开始前安装运行时或依赖项的脚本。
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_OVERRIDES_FILE: dast-api-overrides.json
APISEC_OVERRIDES_CMD: renew_token.py
APISEC_OVERRIDES_INTERVAL: 300调试重写
默认情况下,重写命令的输出是隐藏的。您可以选择将变量 APISEC_OVERRIDES_CMD_VERBOSE 设置为任意值,以将重写命令的输出记录到 gl-api-security-scanner.log 作业工件文件中。这在测试您的重写脚本时很有用,但之后应禁用它,因为它会减慢测试速度。
您还可以将脚本中的消息写入日志文件,该文件会在作业完成或失败时被收集。日志文件必须创建在特定位置并遵循命名约定。
向您的重写脚本添加基本日志记录非常有用,以防脚本在作业的标准运行过程中意外失败。日志文件会自动作为作业的工件包含在内,让您可以在作业完成后下载它。
按照我们的示例,我们在环境变量 APISEC_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('APISEC_OVERRIDES_FILE', 'dast-api-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("重写文件已更新")结束
在 overrides 命令示例中,Python 脚本依赖于 `backoff` 库。为确保在执行 Python 脚本前安装该库,需将 `APISEC_PRE_SCRIPT` 设置为安装 overrides 命令依赖项的脚本。
例如,以下脚本 `user-pre-scan-set-up.sh`
```shell
#!/bin/bash
# user-pre-scan-set-up.sh
# 确保 Python 依赖已安装
echo "**** 安装 Python 依赖 ****"
sudo pip3 install --no-cache --upgrade --break-system-packages \
backoff
echo "**** Python 依赖已安装 ****"
# 结束您必须更新配置以将 APISEC_PRE_SCRIPT 设置为新脚本 user-pre-scan-set-up.sh。例如:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_PRE_SCRIPT: ./user-pre-scan-set-up.sh
APISEC_OVERRIDES_FILE: dast-api-overrides.json
APISEC_OVERRIDES_CMD: renew_token.py
APISEC_OVERRIDES_INTERVAL: 300在前面的示例中,您可以使用 user-pre-scan-set-up.sh 脚本来安装新的运行时或应用程序,之后可以在 overrides 命令中使用它们。
请求头
请求头功能允许您在扫描会话期间指定标头的固定值。例如,您可以使用配置变量 APISEC_REQUEST_HEADERS 在 Cache-Control 标头中设置固定值。如果需要设置的标头包含敏感值(如 Authorization 标头),请结合使用屏蔽变量功能和变量 APISEC_REQUEST_HEADERS_BASE64。
若 Authorization 标头或其他标头需要在扫描进行中更新,请考虑使用overrides 功能。
变量 APISEC_REQUEST_HEADERS 允许您指定一个逗号分隔(,)的标头列表。这些标头会被包含在扫描器执行的每个请求中。列表中的每个标头条目由名称、冒号(:)及其值组成。名称或值前的空白会被忽略。例如,若要声明名为 Cache-Control 且值为 max-age=604800 的标头,条目应为 Cache-Control: max-age=604800。若要使用两个标头 Cache-Control: max-age=604800 和 Age: 100,则将 APISEC_REQUEST_HEADERS 变量设置为 Cache-Control: max-age=604800, Age: 100。
不同标头在 APISEC_REQUEST_HEADERS 变量中提供的顺序不会影响结果。将 APISEC_REQUEST_HEADERS 设为 Cache-Control: max-age=604800, Age: 100 与设为 Age: 100, Cache-Control: max-age=604800 效果相同。
Base64
APISEC_REQUEST_HEADERS_BASE64 变量接受的标头列表与 APISEC_REQUEST_HEADERS 相同,唯一区别是该变量的整个值必须是 Base64 编码的。例如,若要将 APISEC_REQUEST_HEADERS_BASE64 变量设置为 Authorization: QmVhcmVyIFRPS0VO, Cache-control: bm8tY2FjaGU=,请确保将列表转换为 Base64 等价形式:QXV0aG9yaXphdGlvbjogUW1WaGNtVnlJRlJQUzBWTywgQ2FjaGUtY29udHJvbDogYm04dFkyRmphR1U9,并使用 Base64 编码后的值。这在存储秘密标头值于屏蔽变量(存在字符集限制)时很有用。
Base64 用于支持屏蔽变量功能。Base64 编码本身并非安全措施,因为敏感值可轻易解码。
示例:使用纯文本在每个请求中添加标头列表
在以下 .gitlab-ci.yml 示例中,APISEC_REQUEST_HEADERS 配置变量被设置为提供两个标头值,如请求头所述。
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_REQUEST_HEADERS: 'Cache-control: no-cache, Save-Data: on'示例:使用掩码CI/CD变量
以下 .gitlab-ci.yml 示例假设定义了掩码变量 SECRET_REQUEST_HEADERS_BASE64,该变量作为UI中定义的群组或实例CI/CD变量。SECRET_REQUEST_HEADERS_BASE64 的值设置为 WC1BQ01FLVNlY3JldDogc31jcnt0ISwgWC1BQ01FLVRva2VuOiA3MDVkMTZmNWUzZmI=,这是 X-ACME-Secret: s3cr3t!, X-ACME-Token: 705d16f5e3fb 的Base64编码文本版本。然后可以按如下方式使用:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_REQUEST_HEADERS_BASE64: $SECRET_REQUEST_HEADERS_BASE64当将秘密头值存储在掩码变量(具有字符集限制)中时,考虑使用 APISEC_REQUEST_HEADERS_BASE64。
排除路径
测试API时,排除某些路径可能很有用。例如,你可能希望排除对身份验证服务或旧版API的测试。要排除路径,请使用 APISEC_EXCLUDE_PATHS CI/CD变量。此变量在你的 .gitlab-ci.yml 文件中指定。若要排除多个路径,请使用 ; 字符分隔条目。在提供的路径中,你可以使用单字符通配符 ? 和多字符通配符 *。
要验证路径是否被排除,请查看作业输出的“已测试操作”和“已排除操作”部分。你不应在“已测试操作”下看到任何已排除的路径列表。
2021-05-27 21:51:08 [INF] API SECURITY: --[ 已测试操作 ]-------------------------
2021-05-27 21:51:08 [INF] API SECURITY: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API SECURITY: ------------------------------------------------
2021-05-27 21:51:08 [INF] API SECURITY: --[ 已排除操作 ]-----------------------
2021-05-27 21:51:08 [INF] API SECURITY: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API SECURITY: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API SECURITY: ------------------------------------------------示例
此示例排除了 /auth 资源。这不排除子资源(/auth/child)。
variables:
APISEC_EXCLUDE_PATHS: /auth若要排除 /auth 及其子资源(/auth/child),我们使用通配符。
variables:
APISEC_EXCLUDE_PATHS: /auth*若要排除多个路径,我们使用 ; 字符。在此示例中,我们排除 /auth* 和 /v1/*。
variables:
APISEC_EXCLUDE_PATHS: /auth*;/v1/*若要排除路径内的一个或多个嵌套级别,我们使用 **。在此示例中,我们正在测试API端点。我们正在测试数据查询请求 mass、brightness 和 coordinates 数据的 /api/v1/ 和 /api/v2/,对象包括 planet、moon、star 和 satellite。可能扫描的示例路径包括但不限于:
/api/v2/planet/coordinates/api/v1/star/mass/api/v2/satellite/brightness
在此示例中,我们仅测试 brightness 端点:
variables:
APISEC_EXCLUDE_PATHS: /api/**/mass;/api/**/coordinates排除参数
测试API时,你可能希望从测试中排除某个参数(查询字符串、标头或正文元素)。这可能是因为参数总是导致失败、减慢测试速度或其他原因。要排除参数,你可以设置以下变量之一:APISEC_EXCLUDE_PARAMETER_ENV 或 APISEC_EXCLUDE_PARAMETER_FILE。
APISEC_EXCLUDE_PARAMETER_ENV 允许提供包含排除参数的JSON字符串。如果JSON较短且不常更改,这是一个不错的选择。另一个选项是变量 APISEC_EXCLUDE_PARAMETER_FILE。此变量设置为文件路径,该路径可以检入仓库、由其他作业作为工件创建,或在运行时通过预脚本使用 APISEC_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路径排除多个JSON节点
若要排除根级 users 数组中每个条目的 password 属性,需将 body-json 属性的值设为一个包含JSON路径表达式的数组 [ "$.users[*].password" ]。
JSON路径表达式以 $ 开头表示根节点,. 表示当前节点;接着通过 users 引用属性,用 [ 和 ] 包裹要使用的数组索引——此处用 * 替代具体数字来指定任意索引;索引引用后紧跟 .,此时该符号指向数组中被选中的任意索引,其前是属性名 password。
例如,对应的JSON文档如下:
{
"body-json": [ "$.users[*].password" ]
}当请求的内容类型为 application/json 时,排除参数会使用 body-json。body-json 中的每一项都应是一个 JSON Path表达式。在JSON Path中,$、*、. 等字符具有特殊含义。
排除XML属性
若要排除根元素 credentials 中名为 isEnabled 的属性,需将 body-xml 属性的值设为一个包含XPath表达式的数组 [ "/credentials/@isEnabled" ]。
XPath表达式 /credentials/@isEnabled 以 / 开头表示XML文档的根,其后跟随 credentials 指定要匹配的元素名;再用 / 引用前一XML元素的节点,@ 则表明 isEnabled 是属性。
例如,对应的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根节点,其后 credentials 表示XML元素名;接着的 / 引用当前元素,后面跟着新的XML元素名 username;最后的 / 引用当前元素,并使用 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根节点,其后 credentials 表示XML元素名;接着的 / 引用当前元素,后面跟着新的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集合文件中查看命名空间信息。
{
"body-xml": [
"/credentials/s:login"
]
}当请求使用application/xml内容类型时,排除参数会使用body-xml。body-xml中的每一项都应为XPath v2表达式。在XPath中,@、/、:、[、]等字符具有特殊含义。
使用JSON字符串
若要通过JSON文档设置排除规则,可将环境变量APISEC_EXCLUDE_PARAMETER_ENV设为JSON字符串。以下示例展示了如何在.gitlab-ci.yml中设置该变量:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_EXCLUDE_PARAMETER_ENV: '{ "headers": [ "Upgrade-Insecure-Requests" ] }'使用文件
若要通过JSON文档设置排除规则,可将环境变量APISEC_EXCLUDE_PARAMETER_FILE设为JSON文件路径。该路径相对于作业当前工作目录。以下示例展示了如何在.gitlab-ci.yml中设置该变量:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_PROFILE: Quick
APISEC_OPENAPI: test-api-specification.json
APISEC_TARGET_URL: http://test-deployment/
APISEC_EXCLUDE_PARAMETER_FILE: dast-api-exclude-parameters.jsondast-api-exclude-parameters.json是一个遵循排除参数文档结构的JSON文档。
排除URL
作为按路径排除的替代方案,你可通过对URL的其他组件进行过滤来排除请求,方法是使用CI/CD变量APISEC_EXCLUDE_URLS。该变量可在.gitlab-ci.yml文件中设置,支持以逗号分隔的多个值,每个值均为正则表达式。由于每项都是正则表达式,因此类似.*的条目会排除所有URL(因其匹配所有内容)。
你可在作业输出中检查哪些URL匹配了APISEC_EXCLUDE_URLS提供的正则表达式。匹配操作会在Excluded Operations部分列出。这些操作不应出现在Tested Operations部分中。例如以下作业输出的片段:
2021-05-27 21:51:08 [INF] API SECURITY: --[ Tested Operations ]-------------------------
2021-05-27 21:51:08 [INF] API SECURITY: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API SECURITY: ------------------------------------------------
2021-05-27 21:51:08 [INF] API SECURITY: --[ Excluded Operations ]-----------------------
2021-05-27 21:51:08 [INF] API SECURITY: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API SECURITY: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API SECURITY: ------------------------------------------------APISEC_EXCLUDE_URLS中的每个值都是正则表达式。正则表达式中.、*、$等许多字符具有特殊含义。
示例
排除URL及其子资源
以下示例排除了URL http://target/api/auth及其子资源。
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_TARGET_URL: http://target/
APISEC_OPENAPI: test-api-specification.json
APISEC_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:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_TARGET_URL: http://target/
APISEC_OPENAPI: test-api-specification.json
APISEC_EXCLUDE_URLS: http://target/api/buy/$,http://target/api/sell/$排除两个URL及其子资源
若要排除URL:http://target/api/buy 和 http://target/api/sell 及其子资源。提供多个URL时,我们按如下方式使用 , 字符:
stages:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_TARGET_URL: http://target/
APISEC_OPENAPI: test-api-specification.json
APISEC_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:
- dast
include:
- template: API-Security.gitlab-ci.yml
variables:
APISEC_TARGET_URL: http://target/
APISEC_OPENAPI: test-api-specification.json
APISEC_EXCLUDE_URLS: https://target/api/v.*/user/create$