InfoGrab Docs

분석기 설정 사용자 정의

요약

인증은 인증 토큰을 헤더 또는 쿠키로 제공하여 처리됩니다. HTTP 기본 인증은 HTTP 프로토콜에 내장된 인증 방법으로, 전송 계층 보안(TLS)과 함께 사용됩니다. 비밀번호에 대한 CI/CD 변수를 생성하고(예: TEST_API_PASSWORD), 마스킹되도록 설정합니다.

인증#

인증은 인증 토큰을 헤더 또는 쿠키로 제공하여 처리됩니다. 인증 흐름을 수행하거나 토큰을 계산하는 스크립트를 제공할 수 있습니다.

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_BASE64 대신 원시 비밀번호 APISEC_HTTP_PASSWORD를 제공할 수 있습니다.

Bearer 토큰#

Bearer 토큰은 OAuth2 및 JSON 웹 토큰(JWT)을 포함한 여러 다른 인증 메커니즘에서 사용됩니다. Bearer 토큰은 Authorization HTTP 헤더를 사용하여 전송됩니다. API 보안 테스팅에서 Bearer 토큰을 사용하려면 다음 중 하나가 필요합니다:

  • 만료되지 않는 토큰.
  • 테스트 기간 동안 지속되는 토큰을 생성하는 방법.
  • API 보안 테스팅이 호출하여 토큰을 생성할 수 있는 Python 스크립트.

만료되지 않는 토큰#

Bearer 토큰이 만료되지 않는 경우, APISEC_OVERRIDES_ENV 변수를 사용하여 제공합니다. 이 변수의 내용은 API 보안 테스팅을 위한 아웃바운드 HTTP 요청에 추가할 헤더와 쿠키를 제공하는 JSON 스니펫입니다.

APISEC_OVERRIDES_ENV로 Bearer 토큰을 제공하려면 다음 단계를 수행합니다:

  1. 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"}}으로 정의할 수 있습니다.

  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 보안 테스팅을 실행하고 job 로그와 테스트 API 애플리케이션 로그를 검토합니다.

테스트 런타임에 생성된 토큰#

Bearer 토큰을 생성해야 하고 테스팅 중에 만료되지 않는 경우, 토큰이 있는 파일을 API 보안 테스팅에 제공할 수 있습니다. 이전 Stage와 job 또는 API 보안 테스팅 job의 일부가 이 파일을 생성할 수 있습니다.

API 보안 테스팅은 다음 구조의 JSON 파일을 받을 것으로 예상합니다:

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

이 파일은 이전 Stage에서 생성하여 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 보안 테스팅을 실행하고 job 로그와 테스트 API 애플리케이션 로그를 검토합니다.

만료 기간이 짧은 토큰#

Bearer 토큰을 생성해야 하고 스캔이 완료되기 전에 만료되는 경우, API 보안 테스팅 스캐너가 제공된 간격으로 실행할 프로그램 또는 스크립트를 제공할 수 있습니다. 제공된 스크립트는 Python 3와 Bash가 설치된 Alpine Linux 컨테이너에서 실행됩니다. Python 스크립트에 추가 패키지가 필요한 경우, 런타임에 패키지를 감지하여 설치해야 합니다.

스크립트는 특정 형식으로 Bearer 토큰이 포함된 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 보안 테스팅을 실행하고 job 로그와 테스트 API 애플리케이션 로그를 검토합니다. 재정의 명령에 대한 자세한 내용은 재정의 섹션을 참조하세요.

재정의#

API 보안 테스팅은 요청의 특정 항목을 추가하거나 재정의하는 방법을 제공합니다. 예를 들어:

  • 헤더
  • 쿠키
  • 쿼리 문자열
  • 폼 데이터
  • 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="
  }
}

헤더와 쿠키 모두 설정 예시:

{
  "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 변수를 설정합니다. 경로는 job의 현재 작업 디렉터리에 상대적입니다.

.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에 의해 제공된 스크립트는 분석기가 시작되기 전에 한 번 실행됩니다.

Note

권한이 필요한 작업을 수행할 때는 sudo 명령을 사용하세요. 예를 들어, sudo apk add nodejs.

Alpine Linux 패키지 설치에 대한 자세한 내용은 Alpine Linux 패키지 관리 페이지를 참조하세요.

올바른 작동을 위해 각각 설정된 세 개의 CI/CD 변수를 제공해야 합니다:

  • APISEC_OVERRIDES_FILE: 제공된 명령이 생성하는 파일.
  • APISEC_OVERRIDES_CMD: 주기적으로 재정의 JSON 파일을 생성하는 재정의 명령.
  • APISEC_OVERRIDES_INTERVAL: 명령을 실행하는 간격(초).

선택 사항:

  • APISEC_PRE_SCRIPT: 스캔이 시작되기 전에 런타임 또는 의존성을 설치하는 스크립트.
Warning

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 job 아티팩트 파일에 기록할 수 있습니다. 이것은 재정의 스크립트를 테스트할 때 유용하지만, 테스팅이 느려지므로 이후에는 비활성화해야 합니다.

job이 완료되거나 실패할 때 수집되는 로그 파일에 스크립트의 메시지를 기록하는 것도 가능합니다. 로그 파일은 특정 위치에 만들어야 하며 명명 규칙을 따라야 합니다.

재정의 스크립트에 일부 기본 로깅을 추가하는 것은 job의 정상 실행 중에 스크립트가 예기치 않게 실패하는 경우에 유용합니다. 로그 파일은 job의 아티팩트로 자동으로 포함되어 job이 완료된 후 다운로드할 수 있습니다.

이 예시는 환경 변수 APISEC_OVERRIDES_CMDrenew_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('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 the 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 the 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

user-pre-scan-set-up.sh 스크립트로 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_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입니다. 두 헤더인 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로 변환해야 합니다: QXV0aG9yaXphdGlvbjogUW1WaGNtVnlJRlJPUzBWTywgQ2FjaGUtY29udHJvbDogYm04dFkyRmphR1U9, 그리고 Base64로 인코딩된 값을 사용해야 합니다. 이것은 문자 집합 제한이 있는 마스킹된 변수에 비밀 헤더 값을 저장할 때 유용합니다.

Warning

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_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_PATHS CI/CD 변수를 사용합니다. 이 변수는 .gitlab-ci.yml 파일에 지정됩니다. 여러 경로를 제외하려면 ; 문자를 사용하여 항목을 구분합니다. 제공된 경로에서 단일 문자 와일드카드 ?와 다중 문자 와일드카드 *를 사용할 수 있습니다.

경로가 제외되었는지 확인하려면 job 출력의 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/*

경로 내의 하나 이상의 중첩된 레벨을 제외하려면 **를 사용합니다. 다음 예시는 planet, moon, star, satellite 객체에 대해 mass, brightness, coordinates 데이터를 요청하는 데이터 쿼리를 사용하여 /api/v1//api/v2/ API 엔드포인트를 테스트합니다. 스캔될 수 있는 예시 경로는 다음과 같습니다:

  • /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 변수입니다. 이 변수는 저장소에 체크인하거나, 다른 job에서 아티팩트로 만들거나, APISEC_PRE_SCRIPT를 사용하는 사전 스크립트로 런타임에 생성할 수 있는 파일 경로로 설정됩니다.

JSON 문서를 사용한 파라미터 제외#

JSON 문서에는 JSON 객체가 포함되어 있으며, 이 객체는 특정 속성을 사용하여 어떤 파라미터를 제외해야 하는지 식별합니다. 스캔 프로세스 중에 특정 파라미터를 제외하기 위해 다음 속성을 제공할 수 있습니다:

  • headers: 특정 헤더를 제외하기 위해 이 속성을 사용합니다. 속성의 값은 제외할 헤더 이름의 배열입니다. 이름은 대소문자를 구분하지 않습니다.
  • cookies: 특정 쿠키를 제외하기 위해 이 속성의 값을 사용합니다. 속성의 값은 제외할 쿠키 이름의 배열입니다. 이름은 대소문자를 구분합니다.
  • 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-REQUESTSUpgrade-Insecure-Requests와 동일합니다.

헤더와 두 쿠키 모두 제외#

헤더 Authorization과 쿠키 PHPSESSIDcsrftoken을 제외하려면, headers 속성의 값을 헤더 이름이 있는 배열 [ "Authorization" ]으로, 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 Path 표현식은 JSON 노드를 식별하기 위해 특수 구문을 사용합니다: $는 JSON 문서의 루트를 참조하고, .는 현재 객체(이 경우 루트 객체)를 참조하며, 텍스트 schema는 속성 이름을 참조합니다. 따라서, JSON 경로 표현식 $.schema는 루트 객체의 속성 schema를 참조합니다. 예를 들어, JSON 문서는 다음과 같습니다:

{
  "body-json": [ "$.schema" ]
}

제외 파라미터는 요청이 콘텐츠 유형 application/json을 사용할 때 body-json을 사용합니다. body-json의 각 항목은 JSON Path 표현식이어야 합니다. JSON Path에서 $, *, . 등의 문자는 특별한 의미를 가집니다.

JSON Path를 사용하여 여러 JSON 노드 제외#

루트 수준의 users 배열의 각 항목에서 password 속성을 제외하려면, body-json 속성의 값을 JSON Path 표현식 [ "$.users[*].password" ]가 있는 배열로 설정합니다.

JSON Path 표현식은 루트 노드를 참조하기 위해 $로 시작하고, 현재 노드를 참조하기 위해 .를 사용합니다. 그런 다음 속성을 참조하기 위해 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 요소의 노드를 참조하기 위해 /를 사용하고, 이름 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 Collection 파일의 사양 문서에서 네임스페이스를 확인할 수 있습니다.

{
  "body-xml": [
    "/credentials/s:login"
  ]
}

제외 파라미터는 요청이 콘텐츠 유형 application/xml을 사용할 때 body-xml을 사용합니다. body-xml의 각 항목은 XPath v2 표현식이어야 합니다. XPath에서, 표현식 문자인 @, /, :, [, ] 등은 특별한 의미를 가집니다.

JSON 문자열 사용#

제외 JSON 문서를 제공하려면 APISEC_EXCLUDE_PARAMETER_ENV 변수를 JSON 문자열로 설정합니다. 다음 예시에서, .gitlab-ci.ymlAPISEC_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 파일 경로로 설정합니다. 파일 경로는 job의 현재 작업 디렉터리에 상대적입니다. 다음 예시 .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_URLS CI/CD 변수를 사용하여 URL의 다른 구성 요소로 필터링할 수 있습니다. 이 변수는 .gitlab-ci.yml 파일에 설정할 수 있습니다. 변수는 쉼표(,)로 구분된 여러 값을 저장할 수 있습니다. 각 값은 정규 표현식입니다. 각 항목이 정규 표현식이기 때문에, .*와 같은 항목은 모든 것을 일치시키는 정규 표현식이므로 모든 URL을 제외합니다.

job 출력에서 APISEC_EXCLUDE_URLS에서 제공된 정규 표현식과 일치하는 URL이 있는지 확인할 수 있습니다. 일치하는 작업은 Excluded Operations 섹션에 나열됩니다. Excluded Operations에 나열된 작업은 Tested Operations 섹션에 나열되어서는 안 됩니다. 예를 들어 job 출력의 다음 부분:

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: ------------------------------------------------
Note

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/buyhttp://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/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 또는 다른 버전(v3, v4 등)을 제외하려면, https://target/api/v.*/user/create$를 사용합니다. 정규 표현식에서, .는 임의의 문자를 나타내고 *는 0번 이상을 나타냅니다. $는 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$

분석기 설정 사용자 정의

원문 보기
요약

인증은 인증 토큰을 헤더 또는 쿠키로 제공하여 처리됩니다. HTTP 기본 인증은 HTTP 프로토콜에 내장된 인증 방법으로, 전송 계층 보안(TLS)과 함께 사용됩니다. 비밀번호에 대한 CI/CD 변수를 생성하고(예: TEST_API_PASSWORD), 마스킹되도록 설정합니다.

인증#

인증은 인증 토큰을 헤더 또는 쿠키로 제공하여 처리됩니다. 인증 흐름을 수행하거나 토큰을 계산하는 스크립트를 제공할 수 있습니다.

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_BASE64 대신 원시 비밀번호 APISEC_HTTP_PASSWORD를 제공할 수 있습니다.

Bearer 토큰#

Bearer 토큰은 OAuth2 및 JSON 웹 토큰(JWT)을 포함한 여러 다른 인증 메커니즘에서 사용됩니다. Bearer 토큰은 Authorization HTTP 헤더를 사용하여 전송됩니다. API 보안 테스팅에서 Bearer 토큰을 사용하려면 다음 중 하나가 필요합니다:

  • 만료되지 않는 토큰.
  • 테스트 기간 동안 지속되는 토큰을 생성하는 방법.
  • API 보안 테스팅이 호출하여 토큰을 생성할 수 있는 Python 스크립트.

만료되지 않는 토큰#

Bearer 토큰이 만료되지 않는 경우, APISEC_OVERRIDES_ENV 변수를 사용하여 제공합니다. 이 변수의 내용은 API 보안 테스팅을 위한 아웃바운드 HTTP 요청에 추가할 헤더와 쿠키를 제공하는 JSON 스니펫입니다.

APISEC_OVERRIDES_ENV로 Bearer 토큰을 제공하려면 다음 단계를 수행합니다:

  1. 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"}}으로 정의할 수 있습니다.

  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 보안 테스팅을 실행하고 job 로그와 테스트 API 애플리케이션 로그를 검토합니다.

테스트 런타임에 생성된 토큰#

Bearer 토큰을 생성해야 하고 테스팅 중에 만료되지 않는 경우, 토큰이 있는 파일을 API 보안 테스팅에 제공할 수 있습니다. 이전 Stage와 job 또는 API 보안 테스팅 job의 일부가 이 파일을 생성할 수 있습니다.

API 보안 테스팅은 다음 구조의 JSON 파일을 받을 것으로 예상합니다:

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

이 파일은 이전 Stage에서 생성하여 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 보안 테스팅을 실행하고 job 로그와 테스트 API 애플리케이션 로그를 검토합니다.

만료 기간이 짧은 토큰#

Bearer 토큰을 생성해야 하고 스캔이 완료되기 전에 만료되는 경우, API 보안 테스팅 스캐너가 제공된 간격으로 실행할 프로그램 또는 스크립트를 제공할 수 있습니다. 제공된 스크립트는 Python 3와 Bash가 설치된 Alpine Linux 컨테이너에서 실행됩니다. Python 스크립트에 추가 패키지가 필요한 경우, 런타임에 패키지를 감지하여 설치해야 합니다.

스크립트는 특정 형식으로 Bearer 토큰이 포함된 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 보안 테스팅을 실행하고 job 로그와 테스트 API 애플리케이션 로그를 검토합니다. 재정의 명령에 대한 자세한 내용은 재정의 섹션을 참조하세요.

재정의#

API 보안 테스팅은 요청의 특정 항목을 추가하거나 재정의하는 방법을 제공합니다. 예를 들어:

  • 헤더
  • 쿠키
  • 쿼리 문자열
  • 폼 데이터
  • 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="
  }
}

헤더와 쿠키 모두 설정 예시:

{
  "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 변수를 설정합니다. 경로는 job의 현재 작업 디렉터리에 상대적입니다.

.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에 의해 제공된 스크립트는 분석기가 시작되기 전에 한 번 실행됩니다.

Note

권한이 필요한 작업을 수행할 때는 sudo 명령을 사용하세요. 예를 들어, sudo apk add nodejs.

Alpine Linux 패키지 설치에 대한 자세한 내용은 Alpine Linux 패키지 관리 페이지를 참조하세요.

올바른 작동을 위해 각각 설정된 세 개의 CI/CD 변수를 제공해야 합니다:

  • APISEC_OVERRIDES_FILE: 제공된 명령이 생성하는 파일.
  • APISEC_OVERRIDES_CMD: 주기적으로 재정의 JSON 파일을 생성하는 재정의 명령.
  • APISEC_OVERRIDES_INTERVAL: 명령을 실행하는 간격(초).

선택 사항:

  • APISEC_PRE_SCRIPT: 스캔이 시작되기 전에 런타임 또는 의존성을 설치하는 스크립트.
Warning

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 job 아티팩트 파일에 기록할 수 있습니다. 이것은 재정의 스크립트를 테스트할 때 유용하지만, 테스팅이 느려지므로 이후에는 비활성화해야 합니다.

job이 완료되거나 실패할 때 수집되는 로그 파일에 스크립트의 메시지를 기록하는 것도 가능합니다. 로그 파일은 특정 위치에 만들어야 하며 명명 규칙을 따라야 합니다.

재정의 스크립트에 일부 기본 로깅을 추가하는 것은 job의 정상 실행 중에 스크립트가 예기치 않게 실패하는 경우에 유용합니다. 로그 파일은 job의 아티팩트로 자동으로 포함되어 job이 완료된 후 다운로드할 수 있습니다.

이 예시는 환경 변수 APISEC_OVERRIDES_CMDrenew_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('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 the 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 the 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

user-pre-scan-set-up.sh 스크립트로 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_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입니다. 두 헤더인 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로 변환해야 합니다: QXV0aG9yaXphdGlvbjogUW1WaGNtVnlJRlJPUzBWTywgQ2FjaGUtY29udHJvbDogYm04dFkyRmphR1U9, 그리고 Base64로 인코딩된 값을 사용해야 합니다. 이것은 문자 집합 제한이 있는 마스킹된 변수에 비밀 헤더 값을 저장할 때 유용합니다.

Warning

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_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_PATHS CI/CD 변수를 사용합니다. 이 변수는 .gitlab-ci.yml 파일에 지정됩니다. 여러 경로를 제외하려면 ; 문자를 사용하여 항목을 구분합니다. 제공된 경로에서 단일 문자 와일드카드 ?와 다중 문자 와일드카드 *를 사용할 수 있습니다.

경로가 제외되었는지 확인하려면 job 출력의 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/*

경로 내의 하나 이상의 중첩된 레벨을 제외하려면 **를 사용합니다. 다음 예시는 planet, moon, star, satellite 객체에 대해 mass, brightness, coordinates 데이터를 요청하는 데이터 쿼리를 사용하여 /api/v1//api/v2/ API 엔드포인트를 테스트합니다. 스캔될 수 있는 예시 경로는 다음과 같습니다:

  • /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 변수입니다. 이 변수는 저장소에 체크인하거나, 다른 job에서 아티팩트로 만들거나, APISEC_PRE_SCRIPT를 사용하는 사전 스크립트로 런타임에 생성할 수 있는 파일 경로로 설정됩니다.

JSON 문서를 사용한 파라미터 제외#

JSON 문서에는 JSON 객체가 포함되어 있으며, 이 객체는 특정 속성을 사용하여 어떤 파라미터를 제외해야 하는지 식별합니다. 스캔 프로세스 중에 특정 파라미터를 제외하기 위해 다음 속성을 제공할 수 있습니다:

  • headers: 특정 헤더를 제외하기 위해 이 속성을 사용합니다. 속성의 값은 제외할 헤더 이름의 배열입니다. 이름은 대소문자를 구분하지 않습니다.
  • cookies: 특정 쿠키를 제외하기 위해 이 속성의 값을 사용합니다. 속성의 값은 제외할 쿠키 이름의 배열입니다. 이름은 대소문자를 구분합니다.
  • 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-REQUESTSUpgrade-Insecure-Requests와 동일합니다.

헤더와 두 쿠키 모두 제외#

헤더 Authorization과 쿠키 PHPSESSIDcsrftoken을 제외하려면, headers 속성의 값을 헤더 이름이 있는 배열 [ "Authorization" ]으로, 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 Path 표현식은 JSON 노드를 식별하기 위해 특수 구문을 사용합니다: $는 JSON 문서의 루트를 참조하고, .는 현재 객체(이 경우 루트 객체)를 참조하며, 텍스트 schema는 속성 이름을 참조합니다. 따라서, JSON 경로 표현식 $.schema는 루트 객체의 속성 schema를 참조합니다. 예를 들어, JSON 문서는 다음과 같습니다:

{
  "body-json": [ "$.schema" ]
}

제외 파라미터는 요청이 콘텐츠 유형 application/json을 사용할 때 body-json을 사용합니다. body-json의 각 항목은 JSON Path 표현식이어야 합니다. JSON Path에서 $, *, . 등의 문자는 특별한 의미를 가집니다.

JSON Path를 사용하여 여러 JSON 노드 제외#

루트 수준의 users 배열의 각 항목에서 password 속성을 제외하려면, body-json 속성의 값을 JSON Path 표현식 [ "$.users[*].password" ]가 있는 배열로 설정합니다.

JSON Path 표현식은 루트 노드를 참조하기 위해 $로 시작하고, 현재 노드를 참조하기 위해 .를 사용합니다. 그런 다음 속성을 참조하기 위해 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 요소의 노드를 참조하기 위해 /를 사용하고, 이름 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 Collection 파일의 사양 문서에서 네임스페이스를 확인할 수 있습니다.

{
  "body-xml": [
    "/credentials/s:login"
  ]
}

제외 파라미터는 요청이 콘텐츠 유형 application/xml을 사용할 때 body-xml을 사용합니다. body-xml의 각 항목은 XPath v2 표현식이어야 합니다. XPath에서, 표현식 문자인 @, /, :, [, ] 등은 특별한 의미를 가집니다.

JSON 문자열 사용#

제외 JSON 문서를 제공하려면 APISEC_EXCLUDE_PARAMETER_ENV 변수를 JSON 문자열로 설정합니다. 다음 예시에서, .gitlab-ci.ymlAPISEC_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 파일 경로로 설정합니다. 파일 경로는 job의 현재 작업 디렉터리에 상대적입니다. 다음 예시 .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_URLS CI/CD 변수를 사용하여 URL의 다른 구성 요소로 필터링할 수 있습니다. 이 변수는 .gitlab-ci.yml 파일에 설정할 수 있습니다. 변수는 쉼표(,)로 구분된 여러 값을 저장할 수 있습니다. 각 값은 정규 표현식입니다. 각 항목이 정규 표현식이기 때문에, .*와 같은 항목은 모든 것을 일치시키는 정규 표현식이므로 모든 URL을 제외합니다.

job 출력에서 APISEC_EXCLUDE_URLS에서 제공된 정규 표현식과 일치하는 URL이 있는지 확인할 수 있습니다. 일치하는 작업은 Excluded Operations 섹션에 나열됩니다. Excluded Operations에 나열된 작업은 Tested Operations 섹션에 나열되어서는 안 됩니다. 예를 들어 job 출력의 다음 부분:

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: ------------------------------------------------
Note

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/buyhttp://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/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 또는 다른 버전(v3, v4 등)을 제외하려면, https://target/api/v.*/user/create$를 사용합니다. 정규 표현식에서, .는 임의의 문자를 나타내고 *는 0번 이상을 나타냅니다. $는 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$