アナライザー設定をカスタマイズする
APIファジングの動作は、CI/CD変数によって変更できます。
APIファジングの設定ファイルは、リポジトリの.gitlabディレクトリに存在する必要があります。
GitLabセキュリティスキャンツールのすべてのカスタマイズは、これらの変更をデフォルトブランチにマージする前に、マージリクエストでテストする必要があります。そうしないと、誤検出が多数発生するなど、予期しない結果が生じる可能性があります。
認証
認証は、ヘッダーまたはCookieとして認証トークンを提供することで処理されます。認証フローを実行したり、トークンを計算したりするスクリプトを提供できます。
HTTP Basic認証
HTTP Basic認証は、HTTPプロトコルに組み込まれ、トランスポートレイヤーセキュリティ(TLS)と組み合わせて使用される認証方法です。
CI/CD変数を作成して、パスワード(例: TEST_API_PASSWORD)を作成し、マスクするように設定することをお勧めします。GitLabプロジェクトのページの設定 > CI/CDの変数セクションからCI/CD変数を作成できます。マスクされた変数の制限事項により、変数として追加する前に、パスワードをBase64エンコードする必要があります。
最後に、2つの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_PASSWORDRawパスワード
パスワードをBase64エンコードしたくない場合(またはGitLab 15.3以前のバージョンを使用している場合)は、FUZZAPI_HTTP_PASSWORD_BASE64を使用する代わりに、rawパスワードFUZZAPI_HTTP_PASSWORDを指定できます。
Bearerトークン
Bearerトークンは、OAuth2やJSON Webトークン(JWT)など、いくつかの異なる認証メカニズムで使用されます。Bearerトークンは、Authorization HTTPヘッダーを使用して送信されます。APIファジングでベアラートークンを使用するには、次のいずれかが必要です:
- 有効期限切れにならないトークン
- テストの長さに耐えるトークンを生成する方法
- APIファジングが呼び出してトークンを生成できるPythonスクリプト
トークンは有効期限切れになりません
Bearerトークンが有効期限切れにならない場合は、FUZZAPI_OVERRIDES_ENV変数を使用して指定します。この変数のコンテンツは、APIファジングの送信HTTPリクエストに追加するヘッダーとCookieを提供するJSONスニペットです。
FUZZAPI_OVERRIDES_ENVを使用してベアラートークンを提供するには、次の手順に従います:
CI/CD変数を作成します。たとえば、値
{"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}(トークンを代入)を使用してTEST_API_BEARERAUTHを作成します。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ファジングに提供できます。以前のステージングとジョブ、またはAPIファジングジョブの一部で、このファイルを生成できます。
APIファジングは、次の構造のJSONファイルを受信することを想定しています:
{
"headers" : {
"Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}このファイルは、以前のステージングで生成し、FUZZAPI_OVERRIDES_FILECI/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ファザーが指定された間隔で実行するプログラムまたはスクリプトを指定できます。指定されたスクリプトは、Python 3とBashがインストールされているAlpine Linuxパッケージのコンテナで実行されます。Pythonスクリプトが追加のパッケージを必要とする場合は、これを検出し、ランタイム時にパッケージをインストールする必要があります。
スクリプトは、特定の形式でベアラートークンを含むJSONファイルを作成する必要があります:
{
"headers" : {
"Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}正しい操作のために、それぞれ設定された3つの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属性を上書きし、2番目のエントリは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_FILECI/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.jsonCI/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を設定する必要があります。FUZZAPI_PRE_SCRIPTによって提供されるスクリプトは、アナライザーが起動する前に1回実行されます。
昇格された権限を必要とするアクションを実行する場合は、sudoコマンドを使用します。たとえばsudo apk add nodejsなどです。
Alpine Linuxパッケージのインストールについては、Alpine Linuxパッケージのパッケージ管理ページを参照してください。
正しい操作のために、それぞれ設定された3つの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を提供しました。スクリプトには2つの注意点があります:
- ログファイルは、環境変数
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 ****"
# endFUZZAPI_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_PATHSCI/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パス式です。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と同等です。
ヘッダーと2つの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パスを使用した特定のJSONノードの除外
ルートオブジェクトのschemaプロパティを除外するには、body-jsonプロパティの値を、JSONパス式[ "$.schema" ]を持つ配列に設定します。
JSONパス式は、JSONノードを識別するために特別な構文を使用します。$はJSONドキュメントのルートを参照し、.は現在のオブジェクト(この場合、ルートオブジェクト)を参照し、テキストschemaはプロパティ名を参照します。したがって、JSONパス式$.schemaは、ルートオブジェクトのプロパティschemaを参照します。たとえば、JSONドキュメントは次のようになります:
{
"body-json": [ "$.schema" ]
}リクエストがコンテンツタイプapplication/jsonを使用する場合、除外パラメータはbody-jsonを使用します。body-jsonの各エントリは、JSONパス式であることが想定されます。JSONパスでは、$、*、.などの文字には特別な意味があります。
JSONパスを使用した複数のJSONノードの除外
ルートレベルでusersの配列の各エントリにあるプロパティpasswordを除外するには、body-jsonプロパティの値を、JSONパス式[ "$.users[*].paswword" ]を持つ配列に設定します。
JSONパス式は、ルートノードを参照するために$で始まり、現在のノードを参照するために.を使用します。次に、usersを使用してプロパティを参照し、[および]文字を使用して、使用する配列内のインデックスを囲みます。インデックスとして数値を指定する代わりに、*を使用して任意のインデックスを指定します。インデックスの参照の後には、.があり、これは、プロパティ名passwordが前に付いた、配列内の指定されたインデックスを参照します。
たとえば、JSONドキュメントは次のようになります:
{
"body-json": [ "$.users[*].paswword" ]
}リクエストがコンテンツタイプapplication/jsonを使用する場合、除外パラメータはbody-jsonを使用します。body-jsonの各エントリは、JSONパス式であることが想定されます。JSONパスでは、$、*、.などの文字には特別な意味があります。
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で定義され、credentialsルートノードに含まれるXML要素loginを除外するには、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ドキュメントを設定するには、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を除外します。
ジョブの出力で、FUZZAPI_EXCLUDE_URLSから提供された正規表現に一致するURLがあるかどうかを確認できます。一致するオペレーションは、Excluded 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: ------------------------------------------------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/auth2つの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/$を使用できます。この値は2つの正規表現を使用しており、それぞれが,文字で区切られています。したがって、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/$2つの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: trueHeaderFuzzingは、ヘッダーファジングのオン/オフを切り替えるブール値です。デフォルトの設定は、オフの場合は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必要に応じて、各プロファイルに対してこの設定を繰り返します。