분석기 설정 사용자 정의

인증

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

HTTP 기본 인증

HTTP 기본 인증은 HTTP 프로토콜에 내장된 인증 방법으로, 전송 계층 보안(TLS)과 함께 사용됩니다.

비밀번호(예: TEST_API_PASSWORD)에 대한 CI/CD 변수를 생성하고, 이를 마스킹하실 것을 권장합니다. CI/CD 변수를 GitLab 프로젝트 페이지의 Settings > CI/CDVariables 섹션에서 생성할 수 있습니다. 마스킹된 변수의 제한 사항 때문에, 변수를 추가하기 전에 비밀번호를 Base64로 인코딩해야 합니다.

마지막으로, .gitlab-ci.yml 파일에 두 개의 CI/CD 변수를 추가하세요:

  • APISEC_HTTP_USERNAME: 인증을 위한 사용자 이름입니다.
  • APISEC_HTTP_PASSWORD_BASE64: 인증을 위한 Base64 인코딩된 비밀번호입니다.
stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_HAR: test-api-recording.har
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_HTTP_USERNAME: testuser
  APISEC_HTTP_PASSWORD_BASE64: $TEST_API_PASSWORD

원시 비밀번호

비밀번호를 Base64로 인코딩하고 싶지 않거나(GitLab 15.3 이하를 사용하는 경우) APISEC_HTTP_PASSWORD를 제공할 수 있습니다. APISEC_HTTP_PASSWORD_BASE64 대신 사용할 수 있습니다.

베어러 토큰

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

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

토큰이 만료되지 않음

베어러 토큰이 만료되지 않는 경우, APISEC_OVERRIDES_ENV 변수를 사용하여 제공합니다. 이 변수의 내용은 API 보안 테스트를 위해 나가는 HTTP 요청에 추가할 헤더와 쿠키를 제공하는 JSON 스니펫입니다.

APISEC_OVERRIDES_ENV로 베어러 토큰을 제공하는 방법은 다음과 같습니다:

  1. CI/CD 변수를 생성하세요. 예를 들어, TEST_API_BEARERAUTH와 값은 {"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}} (당신의 토큰을 대체하세요). CI/CD 변수는 GitLab 프로젝트 페이지의 Settings > CI/CDVariables 섹션에서 생성할 수 있습니다. 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 보안 테스트를 실행하고 작업 로그 및 테스트 API의 애플리케이션 로그를 검토하세요.

테스트 실행 중 생성된 토큰

Bearer 토큰이 생성되어야 하며 테스트 중에 만료되지 않아야 하는 경우, 토큰이 포함된 파일로 API 보안 테스트를 제공할 수 있습니다. 이전 스테이지와 작업 또는 API 보안 테스트 작업의 일부가 이 파일을 생성할 수 있습니다.

API 보안 테스트는 다음 구조를 갖춘 JSON 파일을 받을 것으로 예상합니다:

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

이 파일은 이전 스테이지에서 생성되어 APISEC_OVERRIDES_FILE CI/CD 변수를 통해 API 보안 테스트에 제공될 수 있습니다.

.gitlab-ci.yml 파일에서 APISEC_OVERRIDES_FILE을 설정하세요:

stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_OPENAPI: test-api-specification.json
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_OVERRIDES_FILE: dast-api-overrides.json

인증이 작동하는지 확인하려면 API 보안 테스트를 실행하고 작업 로그 및 테스트 API의 애플리케이션 로그를 검토하세요.

토큰이 짧은 만료기간을 가질 때

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 보안 테스트를 실행하고 작업 로그 및 테스트 API의 애플리케이션 로그를 검토하세요. 오버라이드 명령에 대한 자세한 정보는 overrides 섹션을 참조하세요.

오버라이드

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

다음은 예제 .gitlab-ci.yml입니다:

stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_OPENAPI: test-api-specification.json
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_OVERRIDES_FILE: dast-api-overrides.json

CI/CD 변수 사용

오버라이드 JSON을 CI/CD 변수로 제공하려면 APISEC_OVERRIDES_ENV 변수를 사용합니다.

이 변수는 마스킹되고 보호될 수 있는 변수로 JSON을 배치할 수 있게 합니다.

이 예제 .gitlab-ci.yml에서는 APISEC_OVERRIDES_ENV 변수를 JSON에 직접 설정합니다:

stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_OPENAPI: test-api-specification.json
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_OVERRIDES_ENV: '{"headers":{"X-API-Version":"2"}}'

이 예제 .gitlab-ci.yml에서는 SECRET_OVERRIDES 변수가 JSON을 제공합니다. 이는 UI에서 정의된 그룹 또는 인스턴스 CI/CD 변수입니다:

stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_OPENAPI: test-api-specification.json
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_OVERRIDES_ENV: $SECRET_OVERRIDES

커맨드 사용

값이 생성되거나 만료 시 재생성되어야 하는 경우, API 보안 테스트 스캐너가 지정된 간격으로 실행할 프로그램이나 스크립트를 제공할 수 있습니다. 제공된 커맨드는 Python 3과 Bash가 설치된 Alpine Linux 컨테이너에서 실행됩니다.

APISEC_OVERRIDES_CMD 환경 변수를 실행하고자 하는 프로그램 또는 스크립트로 설정해야 합니다. 제공된 커맨드는 이전에 정의된 오버라이드 JSON 파일을 생성합니다.

NodeJS나 Ruby와 같은 다른 스크립팅 런타임을 설치하거나 오버라이드 명령에 대한 종속성을 설치해야 할 수도 있습니다. 이 경우, APISEC_PRE_SCRIPT를 해당 요구 사항을 제공하는 스크립트의 파일 경로로 설정해야 합니다. APISEC_PRE_SCRIPT로 제공된 스크립트는 분석기가 시작되기 전에 한 번 실행됩니다.

참고: 승격된 권한이 필요한 작업을 수행할 때는 sudo 명령을 사용하세요. 예를 들어, sudo apk add nodejs입니다.

Alpine Linux 패키지 설치에 대한 정보는 Alpine Linux 패키지 관리 페이지를 참조하세요.

올바른 작동을 위해 세 가지 CI/CD 변수를 제공해야 합니다:

  • APISEC_OVERRIDES_FILE: 제공된 커맨드에 의해 생성된 파일입니다.
  • APISEC_OVERRIDES_CMD: 주기적으로 오버라이드 JSON 파일을 생성하는 커맨드입니다.
  • APISEC_OVERRIDES_INTERVAL: 커맨드를 실행하는 간격(초)입니다.

선택적으로:

  • APISEC_PRE_SCRIPT: 스캔 시작 전에 런타임이나 종속성을 설치하는 스크립트입니다.

경고: 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를 제공했습니다. 스크립트에서 두 가지 사항에 주의하세요:

  • 로그 파일은 환경 변수 CI_PROJECT_DIR에 의해 지정된 위치에 저장됩니다.
  • 로그 파일 이름은 gl-*.log 패턴과 일치해야 합니다.
#!/usr/bin/env python

# 오버라이드 명령의 예

# 오버라이드 명령은 새로운 값을 사용하여 
# 오버라이드 json 파일을 업데이트할 수 있습니다. 
# 이는 테스트 중 만료될 수 있는 
# 인증 토큰을 업데이트하는 훌륭한 방법입니다.

import logging
import json
import os
import requests
import backoff

# [1] 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] 파일 이름은 패턴에 맞아야 합니다: gl-*.log
log_file_path = os.path.join(working_directory, 'gl-user-overrides.log')

# 로거 설정
logging.basicConfig(filename=log_file_path, level=logging.DEBUG)

# `backoff` 데코레이터를 사용하여 일시적인 오류 발생 시 재시도합니다.
@backoff.on_exception(backoff.expo,
                      (requests.exceptions.Timeout,
                       requests.exceptions.ConnectionError),
                       max_time=30)
def get_auth_response():
    authorization_url = 'https://authorization.service/api/get_api_token'
    return requests.get(
        f'{authorization_url}',
        auth=(os.environ.get('AUTH_USER'), os.environ.get('AUTH_PWD'))
    )

# 이 예제에서는 주어진 엔드포인트에서 액세스 토큰을 검색합니다
try:

    # HTTP 요청을 수행합니다. 응답 예:
    # { "Token" : "abcdefghijklmn" }
    response = get_auth_response()

    # 요청이 성공했는지 확인합니다. `requests.exceptions.HTTPError`를 발생시킬 수 있습니다.
    response.raise_for_status()

    # JSON 데이터를 가져옵니다
    response_body = response.json()

# 필요한 경우 특정 예외를 잡을 수 있습니다
# requests.ConnectionError                  : 네트워크 연결 오류가 발생했습니다.
# requests.HTTPError                        : HTTP 요청이 성공적이지 않은 상태 코드를 반환했습니다. [Response.raise_for_status()]
# requests.ConnectTimeout                   : 원격 서버에 연결하는 동안 요청 시간이 초과되었습니다.
# requests.ReadTimeout                      : 서버가 할당된 시간 내에 데이터를 전송하지 않았습니다.
# requests.TooManyRedirects                 : 요청이 설정된 최대 리디렉션 수를 초과했습니다.
# requests.exceptions.RequestException      : Requests와 관련된 모든 예외
except json.JSONDecodeError as json_decode_error:
    # JSON 응답 디코딩 중 오류 기록
    logging.error(f'오류, JSON 응답 디코딩 중 실패. 오류 메시지: {json_decode_error}')
    raise
except requests.exceptions.RequestException as requests_error:
    # `Requests`와 관련된 예외 기록
    logging.error(f'오류, HTTP 요청 수행 중 실패. 오류 메시지: {requests_error}')
    raise
except Exception as e:
    # 다른 모든 오류 기록
    logging.error(f'오류, 액세스 토큰을 검색하는 동안 알 수 없는 오류 발생. 오류 메시지: {e}')
    raise

# 요청에서 가져온 데이터를 사용하여 오버라이드 파일 내용이 들어 있는 객체를 계산합니다.
overrides_data = {
    "headers": {
        "Authorization": f"Token {response_body['Token']}"
    }
}

# 파일 오버라이드 계산에 대한 로그 항목
logging.info("오버라이드 파일 생성 중: %s" % overrides_file_path)

# 파일을 덮어쓰려 시도합니다
try:
    if os.path.exists(overrides_file_path):
        os.unlink(overrides_file_path)

    # 업데이트된 사전으로 파일을 덮어씁니다
    with open(overrides_file_path, "wb+") as fd:
        fd.write(json.dumps(overrides_data).encode('utf-8'))
except Exception as e:
    # 다른 모든 오류 기록
    logging.error(f'오류, 파일 {overrides_file_path}를 덮어쓰는 중 알 수 없는 오류 발생. 오류 메시지: {e}')
    raise

# 오버라이드가 성공적으로 완료되었음을 알리는 로그
logging.info("오버라이드 파일이 업데이트되었습니다")

# 끝

오버라이드 명령 예제에서 Python 스크립트는 backoff 라이브러리에 의존합니다. Python 스크립트를 실행하기 전에 라이브러리가 설치되도록 보장하기 위해, APISEC_PRE_SCRIPT는 오버라이드 명령의 종속성을 설치하는 스크립트로 설정됩니다. 예를 들어, 다음 스크립트 user-pre-scan-set-up.sh

#!/bin/bash

# user-pre-scan-set-up.sh
# Python 종속성이 설치되도록 보장합니다.

echo "**** Python 종속성 설치 ****"

sudo pip3 install --no-cache --upgrade --break-system-packages \
    backoff

echo "**** Python 종속성이 설치되었습니다 ****"

# 끝

구성을 업데이트하여 APISEC_PRE_SCRIPT를 새로운 user-pre-scan-set-up.sh 스크립트로 설정해야 합니다. 예를 들어:

stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_OPENAPI: test-api-specification.json
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_PRE_SCRIPT: ./user-pre-scan-set-up.sh
  APISEC_OVERRIDES_FILE: dast-api-overrides.json
  APISEC_OVERRIDES_CMD: renew_token.py
  APISEC_OVERRIDES_INTERVAL: 300

이전 샘플에서는 스크립트 user-pre-scan-set-up.sh를 사용하여 나중에 오버라이드 명령에서 사용할 수 있는 새로운 런타임이나 애플리케이션을 설치할 수도 있습니다.

요청 헤더

요청 헤더 기능을 사용하면 스캔 세션 동안 헤더의 고정 값을 지정할 수 있습니다. 예를 들어, 구성 변수 APISEC_REQUEST_HEADERS를 사용하여 Cache-Control 헤더에 고정 값을 설정할 수 있습니다. 설정해야 하는 헤더에 Authorization 헤더와 같은 민감한 값이 포함되어 있으면, 마스킹 변수 기능과 함께 변수 APISEC_REQUEST_HEADERS_BASE64를 사용하세요.

스캔이 진행되는 동안 Authorization 헤더 또는 기타 헤더를 업데이트해야 하는 경우, 오버라이드 기능을 사용하는 것을 고려하세요.

변수 APISEC_REQUEST_HEADERS를 사용하면 쉼표로 구분된(,) 헤더 목록을 지정할 수 있습니다. 이 헤더는 스캐너가 수행하는 각 요청에 포함됩니다. 목록의 각 헤더 항목은 이름 다음에 콜론(:)과 값이 뒤따릅니다. 키 또는 값 앞의 공백은 무시됩니다. 예를 들어, Cache-Control 헤더 이름을 max-age=604800 값으로 선언하려면 헤더 항목은 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에 해당하는 값으로 변환해야 합니다: QXV0aG9yaXphdGlvbjogUW1WaGNtVnlJRlJQUzBWTywgQ2FjaGUtY29udHJvbDogYm04dFkyRmphR1U9, 그리고 Base64로 인코딩된 값을 사용해야 합니다. 이는 마스킹 변수에 비밀 헤더 값을 저장할 때 유용하며, 여기에는 문자 집합 제한이 있습니다.

경고: Base64는 마스킹 변수 기능을 지원하는 데 사용됩니다. Base64 인코딩 자체는 보안 조치가 아니며, 민감한 값을 쉽게 디코딩할 수 있습니다.

예제: 일반 텍스트를 사용하여 각 요청에 헤더 목록 추가하기

다음의 .gitlab-ci.yml 예제에서, APISEC_REQUEST_HEADERS 구성 변수를 설정하여 요청 헤더에서 설명한 대로 두 개의 헤더 값을 제공합니다.

stages:
  - dast

include:
  - template: API-Security.gitlab-ci.yml

variables:
  APISEC_PROFILE: Quick
  APISEC_OPENAPI: test-api-specification.json
  APISEC_TARGET_URL: http://test-deployment/
  APISEC_REQUEST_HEADERS: 'Cache-control: no-cache, Save-Data: on'

예제: 마스킹된 CI/CD 변수를 사용하는 방법

다음 .gitlab-ci.yml 샘플은 마스킹된 변수 SECRET_REQUEST_HEADERS_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 파일에서 지정됩니다. 여러 경로를 제외하려면 항목을 ; 문자로 구분하십시오. 제공된 경로에서는 단일 문자 와일드카드 ? 및 다중 문자 와일드카드 *를 사용할 수 있습니다.

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

경로 내에서 하나 이상의 중첩 수준을 제외하려면 **를 사용합니다. 이 예에서는 API 엔드포인트를 테스트하고 있습니다. 우리는 planet, moon, star, satellite 객체에 대한 mass, brightnesscoordinates 데이터 요청을 위한 /api/v1//api/v2/를 테스트하고 있습니다. 스캔할 수 있는 예제 경로는 다음과 같습니다(제한되지 않음):

  • /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: 특정 쿠키를 제외하기 위해 이 속성의 값을 사용합니다. 속성의 값은 제외할 쿠키 이름의 배열입니다. 이름은 대소문자를 구분합니다.

  • 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 헤더와 PHPSESSID, csrftoken 쿠키를 제외하려면, 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 Path 표현식 $.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 요소의 노드를 참조하기 위해 /를 사용하고, @ 문자를 사용하여 isEnabled라는 이름이 속성임을 나타냅니다.

예를 들어, JSON 문서는 다음과 같이 보입니다:

{
  "body-xml": [
    "/credentials/@isEnabled"
  ]
}

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

XML 텍스트 요소 제외하기

루트 노드 credentials에 포함된 username 요소의 텍스트를 제외하려면 body-xml 속성의 값을 XPath 표현식 [/credentials/username/text()" ]을 사용하는 배열로 설정합니다.

XPath 표현식 /credentials/username/text()에서 첫 번째 문자 /는 루트 XML 노드를 나타내며, 그 다음에 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에 정의된 XML 요소 login을 제외하고 루트 노드 credentials에 포함된 경우, body-xml 속성의 값을 XPath 표현식 [ "/credentials/s:login" ]을 사용하는 배열로 설정합니다.

XPath 표현식 /credentials/s:login에서 첫 번째 문자 /는 루트 XML 노드를 나타내며, 그 다음에 XML 요소의 이름 credentials를 나타냅니다. 마찬가지로 문자 /는 현재 요소를 참조하고, 그 뒤에 새로운 XML 요소의 이름 s:login이 옵니다. 주목할 점은 이름에 문자 :가 포함되어 있으며, 이 문자는 네임스페이스와 노드 이름을 구분합니다.

네임스페이스 이름은 HTTP 본문 요청의 일부인 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_URLS CI/CD 변수를 사용하여 URL의 다른 구성 요소로 필터링할 수 있습니다. 이 변수는 .gitlab-ci.yml 파일에 설정할 수 있습니다. 변수는 여러 값을 쉼표(,)로 구분하여 저장할 수 있습니다. 각 값은 정규 표현식입니다. 각 항목이 정규 표현식이기 때문에 .*와 같은 항목은 모든 URL을 제외합니다. 이는 모든 항목과 일치하는 정규 표현식입니다.

작업 출력에서 APISEC_EXCLUDE_URLS에서 제공된 정규 표현식과 일치하는 URL이 있는지 확인할 수 있습니다. 일치하는 작업은 제외된 작업 섹션에 나열됩니다. 제외된 작업에 나열된 작업은 테스트된 작업 섹션에 나열되지 않아야 합니다. 예를 들어 아래 작업 출력의 일부:

2021-05-27 21:51:08 [INF] API SECURITY: --[ 테스트된 작업 ]-------------------------
2021-05-27 21:51:08 [INF] API SECURITY: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API SECURITY: ------------------------------------------------
2021-05-27 21:51:08 [INF] API SECURITY: --[ 제외된 작업 ]-----------------------
2021-05-27 21:51:08 [INF] API SECURITY: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API SECURITY: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API SECURITY: ------------------------------------------------
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$