正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

アナライザー設定をカスタマイズする

認証

認証は、認証トークンをヘッダーまたはCookieとして提供することで処理されます。認証フローを実行するか、トークンを計算するスクリプトを提供できます。

HTTP基本認証

HTTP Basic認証は、HTTPプロトコルに組み込まれ、トランスポートレイヤーセキュリティ(TLS)と組み合わせて使用される認証方法です。

パスワードにはCI/CD変数を作成(例: TEST_API_PASSWORD)し、マスクされた変数に設定することをお勧めします。GitLabプロジェクトのページで、設定 > CI/CD変数セクションからCI/CD変数を作成できます。マスクされた変数の制限のため、変数として追加する前に、パスワードをBase64でエンコードする必要があります。

最後に、.gitlab-ci.ymlファイルに2つの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

Rawパスワード

パスワードをBase64でエンコードしない場合(またはGitLabバージョン15.3以前のバージョンを使用している場合)、APISEC_HTTP_PASSWORD_BASE64を使用する代わりに、rawパスワードAPISEC_HTTP_PASSWORDを指定できます。

ベアラートークン

ベアラートークンは、OAuth2やJSON Webトークン(JWT)など、いくつかの異なる認証メカニズムで使用されます。ベアラートークンは、Authorization HTTPヘッダーを使用して送信されます。APIセキュリティテストでベアラートークンを使用するには、次のいずれかが必要です:

  • 有効期限切れにならないトークン。
  • テストの長さに耐えるトークンを生成する方法。
  • APIセキュリティテストが呼び出してトークンを生成できるPythonスクリプト。

トークンは有効期限切れにならない

ベアラートークンが有効期限切れにならない場合は、APISEC_OVERRIDES_ENV変数を使用して指定します。この変数のコンテンツは、APIセキュリティテストの発信HTTPリクエストに追加するヘッダーとCookieを提供するJSONスニペットです。

次の手順に従って、APISEC_OVERRIDES_ENVでベアラートークンを指定します:

  1. CI/CD変数を作成します。たとえば、値{"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}(トークンを代入)を持つTEST_API_BEARERAUTHなどです。GitLabプロジェクトのページで、設定 > CI/CD変数セクションからCI/CD変数を作成できます。TEST_API_BEARERAUTHの形式のため、変数をマスクすることはできません。トークンの値をマスクするには、トークン値を持つ2番目の変数を作成し、値{"headers":{"Authorization":"Bearer $MASKED_VARIABLE"}}TEST_API_BEARERAUTHを定義します。

  2. .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
  3. 認証が機能していることを検証するには、APIセキュリティテストを実行し、ジョブログとテストAPIのアプリケーションログファイルを確認します。

テストランタイムで生成されたトークン

ベアラートークンを生成する必要があり、テスト中に有効期限が切れない場合は、トークンを含むファイルをAPIセキュリティテストに提供できます。前のステージングとジョブ、またはAPIセキュリティテストジョブの一部で、このファイルを生成できます。

APIセキュリティテストでは、次の構造のJSONファイルを受け取ることを想定しています:

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

このファイルは、前のステージングで生成し、APISEC_OVERRIDES_FILECI/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のアプリケーションログファイルを確認します。

トークンの有効期限が短い

ベアラートークンを生成する必要があり、スキャンの完了前に有効期限が切れる場合は、APIセキュリティテストスキャナーが指定された間隔で実行するプログラムまたはスクリプトを提供できます。指定されたスクリプトは、Python 3とBashがインストールされたAlpine Linuxコンテナで実行されます。Pythonスクリプトに追加の依存関係パッケージが必要な場合は、これを検出し、ランタイム時にパッケージをインストールする必要があります。

スクリプトは、特定の形式でベアラートークンを含むJSONファイルを作成する必要があります:

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

3つの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セキュリティテストには、リクエスト内の特定の項目を追加またはオーバーライドする方法が用意されています。次に例を示します:

  • ヘッダー
  • 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をファイルとして指定するには、APISEC_OVERRIDES_FILECI/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によって提供されるスクリプトが1回実行されます。

昇格された権限を必要とするアクションを実行する場合は、sudoコマンドを使用します。たとえばsudo apk add nodejsなどです。

Alpine Linuxパッケージのインストールについては、Alpine Linuxパッケージ管理ページを参照してください。

3つのCI/CD変数を指定する必要があります。各変数は正しく動作するように設定されています:

  • APISEC_OVERRIDES_FILE: 指定されたコマンドによって生成されたファイル。
  • APISEC_OVERRIDES_CMD: JSONファイルを定期的に生成するオーバーライドコマンド。
  • APISEC_OVERRIDES_INTERVAL: コマンドを実行する間隔(秒単位)。

オプション:

  • APISEC_PRE_SCRIPT: スキャンが開始される前にランタイムまたは依存関係をインストールするスクリプト。

Alpine Linuxでスクリプトを実行するには、まずコマンドchmodを使用して、実行権限を設定する必要があります。たとえば、全員に対してscript.pyの実行権限を設定するには、コマンドsudo chmod a+x script.pyを使用します。必要に応じて、実行権限がすでに設定されているscript.pyをバージョン管理できます。

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_CMDrenew_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('APISEC_OVERRIDES_FILE', 'dast-api-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スクリプトを実行する前にライブラリがインストールされていることを確認するために、APISEC_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 \
    backoff

echo "**** python dependencies installed ****"

# end

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を使用して、後で使用できる新しいランタイムまたはアプリケーションをインストールすることもできます。

リクエストヘッダー

リクエストヘッダー機能を使用すると、スキャンセッション中にヘッダーの固定値を指定できます。たとえば、設定変数APISEC_REQUEST_HEADERSを使用して、Cache-Controlヘッダーに固定値を設定できます。設定する必要があるヘッダーにAuthorizationヘッダーなどの機密値が含まれている場合は、マスクされた変数機能と変数APISEC_REQUEST_HEADERS_BASE64を組み合わせて使用します。

Authorizationヘッダーまたはその他のヘッダーをスキャンの進行中に更新する必要がある場合は、オーバーライド機能の使用を検討してください。

変数APISEC_REQUEST_HEADERSを使用すると、カンマ(,)で区切られたヘッダーのリストを指定できます。これらのヘッダーは、スキャナーが実行する各リクエストに含まれます。リスト内の各ヘッダーエントリは、名前、その後にコロン(:)、その後に値で構成されます。キーまたは値の前の空白は無視されます。たとえば、値max-age=604800を持つヘッダー名Cache-Controlを宣言する場合、ヘッダーエントリはCache-Control: max-age=604800です。2つのヘッダー、Cache-Control: max-age=604800Age: 100を使用するには、APISEC_REQUEST_HEADERS変数をCache-Control: max-age=604800, Age: 100に設定します。

変数APISEC_REQUEST_HEADERSに異なるヘッダーが提供される順序は、結果に影響しません。APISEC_REQUEST_HEADERSCache-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設定変数が、リクエストヘッダーで説明されているように、2つのヘッダー値を提供するように設定されています。

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_BASE64UIで定義されたグループまたはインスタンス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_PATHSCI/CD変数を使用します。この変数は、.gitlab-ci.ymlファイルで指定します。複数のパスを除外するには、;文字を使用してエントリを区切ります。指定されたパスでは、単一文字のワイルドカード?と、複数文字のワイルドカードに*を使用できます。

パスが除外されていることを確認するには、ジョブ出力のTested OperationsExcluded 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: ------------------------------------------------

この例では、/authリソースを除外しています。これは、子リソース(/auth/child)を除外するものではありません。

variables:
  APISEC_EXCLUDE_PATHS: /auth

/authと子リソース(/auth/child)を除外するには、ワイルドカードを使用します。

variables:
  APISEC_EXCLUDE_PATHS: /auth*

複数のパスを除外するには、;文字を使用します。この例では、/auth*/v1/*を除外します。

variables:
  APISEC_EXCLUDE_PATHS: /auth*;/v1/*

パス内の1つ以上のネストされたレベルを除外するには、**を使用します。この例では、APIエンドポイントをテストしています。/api/v1//api/v2/のデータクエリをテストしており、massbrightnesscoordinatesのデータを、planetmoonstarsatelliteオブジェクトに対してリクエストします。スキャンできるパスの例を次に示しますが、これらに限定されません:

  • /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パス式です。
  • 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-REQUESTSUpgrade-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[*].password" ]を持つ配列に設定します。

JSONパス式は、ルートノードを参照するために$で始まり、現在のノードを参照するために.を使用します。次に、usersを使用してプロパティを参照し、使用する配列のインデックスを囲むために文字[]を使用します。インデックスとして数値を指定する代わりに、*を使用して任意のインデックスを指定します。インデックス参照の後には、.があり、これは属性名passwordが前に付いた、指定された任意の選択された配列内のインデックスを参照するようになりました。

たとえば、JSONドキュメントは次のようになります:

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

リクエストがコンテンツタイプ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ルートノードに含まれるanXML要素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ドキュメントを提供するには、変数APISEC_EXCLUDE_PARAMETER_ENVにJSON文字列を設定します。次の例では、.gitlab-ci.ymlで、APISEC_EXCLUDE_PARAMETER_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_EXCLUDE_PARAMETER_ENV: '{ "headers": [ "Upgrade-Insecure-Requests" ] }'

ファイルの使用

除外JSONドキュメントを提供するには、変数APISEC_EXCLUDE_PARAMETER_FILEにJSONファイルのパスを設定します。ファイルのパスは、ジョブの現在の作業ディレクトリに対する相対パスです。次の例.gitlab-ci.ymlのコンテンツでは、APISEC_EXCLUDE_PARAMETER_FILE変数は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_EXCLUDE_PARAMETER_FILE: dast-api-exclude-parameters.json

dast-api-exclude-parameters.jsonは、パラメータを除外するドキュメントの構造に従うJSONドキュメントです。

URLの除外

パスで除外する代わりに、APISEC_EXCLUDE_URLSCI/CD変数を使用して、URLの他のコンポーネントでフィルタリングできます。この変数は、.gitlab-ci.ymlファイルで設定できます。この変数には、カンマ(,)で区切られた複数の値を格納できます。各値は、正規表現です。各エントリが正規表現であるため、.*のようなエントリは、すべてに一致する正規表現であるため、すべてのURLを除外します。

ジョブの出力で、APISEC_EXCLUDE_URLSから提供された正規表現に一致するURLがあるかどうかを確認できます。一致するオペレーションは、Excluded Operations(除外されたオペレーション)セクションにリストされています。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
2つの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/$の値を使用できます。この値は、それぞれが,文字で区切られた2つの正規表現を使用しています。したがって、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/$
2つのURLとその子リソースの除外

URL http://target/api/buyhttp://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/createhttps://target/api/v2/user/create、またはその他のバージョン(v3v4など)を正確に除外するには、次のようにします。前の正規表現では、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$