분석기 설정 사용자 정의

API 퍼징 동작은 CI/CD 변수를 통해 변경할 수 있습니다.

GitLab 13.12 이후, 기본 API 퍼징 구성 파일은 .gitlab/gitlab-api-fuzzing-config.yml입니다. GitLab 14.0 이후에는 API 퍼징 구성 파일은 리포지토리의 루트가 아닌 .gitlab 디렉토리에 있어야 합니다.

경고: GitLab 보안 스캔 도구의 모든 사용자 정의는 기본 브랜치로 변경 사항을 병합하기 전에 병합 요청에서 테스트되어야 합니다. 그렇지 않으면 예상치 못한 결과가 발생할 수 있으며, 거짓 양성이 많이 발생할 수 있습니다.

인증

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

HTTP 기본 인증

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

비밀번호에 대한 CI/CD 변수(예: TEST_API_PASSWORD)를 만들고 해당 변수를 마스킹된 상태로 설정하는 것을 권장합니다. GitLab 프로젝트 페이지의 설정 > CI/CD에서 Variables 섹션에서 CI/CD 변수를 생성할 수 있습니다. 마스킹된 변수의 제한 사항으로 인해 변수에 추가하기 전에 비밀번호를 Base64로 인코딩해야 합니다.

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

  • FUZZAPI_HTTP_USERNAME: 인증을 위한 사용자 이름.
  • FUZZAPI_HTTP_PASSWORD_BASE64: 인증을 위한 Base64로 인코딩된 비밀번호.
stages:
    - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick-10
  FUZZAPI_HAR: test-api-recording.har
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_HTTP_USERNAME: testuser
  FUZZAPI_HTTP_PASSWORD_BASE64: $TEST_API_PASSWORD

원시 비밀번호

비밀번호를 Base64로 인코딩하지 않으려면(또는 GitLab 15.3 이전을 사용하는 경우) FUZZAPI_HTTP_PASSWORD_BASE64 대신 원시 비밀번호 FUZZAPI_HTTP_PASSWORD를 제공할 수 있습니다.

Bearer 토큰

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

  • 만료되지 않는 토큰
  • 테스트 기간 동안 유효한 토큰 생성 방법
  • API 퍼징에서 토큰을 생성하도록 호출할 수 있는 Python 스크립트

토큰이 만료되지 않음

Bearer 토큰이 만료되지 않는 경우 FUZZAPI_OVERRIDES_ENV 변수를 사용하여 제공하세요. 이 변수의 내용은 API 퍼징의 외부 HTTP 요청에 추가할 헤더 및 쿠키를 제공하는 JSON 스니펫입니다.

FUZZAPI_OVERRIDES_ENV에 Bearer 토큰을 제공하려면 다음 단계를 따르세요:

  1. 예를 들어 TEST_API_BEARERAUTH의 값이 {"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}(토큰을 대체)인 CI/CD 변수를 생성합니다. GitLab 프로젝트 페이지의 설정 > CI/CD에서 Variables 섹션에서 CI/CD 변수를 생성할 수 있습니다.

  2. .gitlab-ci.yml 파일에서 FUZZAPI_OVERRIDES_ENV를 방금 생성한 변수로 설정하세요:

    stages:
      - fuzz
    
    include:
      - template: API-Fuzzing.gitlab-ci.yml
    
    variables:
      FUZZAPI_PROFILE: Quick-10
      FUZZAPI_OPENAPI: test-api-specification.json
      FUZZAPI_TARGET_URL: http://test-deployment/
      FUZZAPI_OVERRIDES_ENV: $TEST_API_BEARERAUTH
    
  3. 인증이 작동하는지 확인하려면 API 퍼징 테스트를 실행하고 퍼징 로그와 테스트 API의 응용 프로그램 로그를 검토하세요. 자세한 정보는 overrides section을 참조하세요.

테스트 실행 중 생성된 토큰

Bearer 토큰이 생성되어 테스트 기간 동안 만료되지 않는 경우, 이 토큰이 포함된 파일을 API 퍼징에 제공할 수 있습니다. 이 파일은 이전 단계 및 작업 또는 API 퍼징 작업의 일부에 의해 생성될 수 있습니다.

API 퍼징은 다음 구조의 JSON 파일을 받도록 기대합니다:

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

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

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json

인증이 작동하는지 확인하려면 API 퍼징 테스트를 실행하고 퍼징 로그와 테스트 API의 응용 프로그램 로그를 검토하세요.

토큰의 짧은 만료 기간

만일 베어러 토큰이 스캔이 완료되기 전에 생성되고 만료되어야 하는 경우, API 퍼저에게 지정된 간격에서 실행할 프로그램이나 스크립트를 제공할 수 있습니다. 제공된 스크립트는 Python 3과 Bash가 설치된 Alpine Linux 컨테이너에서 실행됩니다. Python 스크립트가 추가 패키지를 필요로 하는 경우, 실행 중에 패키지를 감지하고 설치해야 합니다.

스크립트는 베어러 토큰을 특정 형식으로 포함하는 JSON 파일을 생성해야 합니다:

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

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

  • FUZZAPI_OVERRIDES_FILE: 제공된 명령이 생성한 JSON 파일
  • FUZZAPI_OVERRIDES_CMD: JSON 파일을 생성하는 명령
  • FUZZAPI_OVERRIDES_INTERVAL: 명령을 실행하는 간격(초 단위)

예시:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick-10
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
  FUZZAPI_OVERRIDES_CMD: renew_token.py
  FUZZAPI_OVERRIDES_INTERVAL: 300

인증이 작동하는지 확인하려면 API 퍼징 테스트를 실행하고 퍼징 로그 및 테스트 API 응용프로그램 로그를 검토하세요.

API 퍼징 프로필

GitLab은 다음과 같은 gitlab-api-fuzzing-config.yml이라는 구성 파일을 제공합니다. 이 파일에는 여러 가지의 테스트 프로필이 포함되어 있으며, 각 프로필의 실행 시간은 테스트 횟수가 증가함에 따라 증가합니다.

프로필 Fuzz 테스트(매개변수당)
Quick-10 10
Medium-20 20
Medium-50 50
Long-100 100

오버라이드

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.$"
  }
}

각 JSON 속성 이름은 JSON Path 표현식으로 설정됩니다. JSON Path 표현식 $.credentials.access-tokeniddqd!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.$"
  }
}

각 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을 파일로 제공하려면 FUZZAPI_OVERRIDES_FILE CI/CD 변수를 설정합니다. 경로는 작업의 현재 작업 디렉토리를 기준으로 상대적입니다.

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

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json

CI/CD 변수 사용

오버라이드 JSON을 CI/CD 변수로 제공하려면 FUZZAPI_OVERRIDES_ENV 변수를 사용합니다. 이를 통해 JSON을 변수로 배치할 수 있으며, 이 변수는 가려지고 보호될 수 있습니다.

다음은 이 .gitlab-ci.yml의 예시입니다. FUZZAPI_OVERRIDES_ENV 변수는 JSON으로 직접 설정됩니다.

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_ENV: '{"headers":{"X-API-Version":"2"}}'

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

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_ENV: $SECRET_OVERRIDES

명령어 사용

값이 생성되거나 만료 후에 다시 생성해야 하는 경우 API 퍼저가 지정된 간격에서 실행할 프로그램이나 스크립트를 제공할 수 있습니다. 제공된 스크립트는 Python 3 및 Bash가 설치된 Alpine Linux 컨테이너에서 실행됩니다.

환경 변수 FUZZAPI_OVERRIDES_CMD를 원하는 프로그램이나 스크립트로 설정해야 합니다. 제공된 명령은 이전에 정의한 대로 오버라이드 JSON 파일을 생성합니다.

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

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

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

  • FUZZAPI_OVERRIDES_FILE: 제공된 명령으로 생성된 파일
  • FUZZAPI_OVERRIDES_CMD: 오버라이드 JSON 파일을 주기적으로 생성하는 오버라이드 명령
  • FUZZAPI_OVERRIDES_INTERVAL: 명령 실행 간격(초)

옵션:

  • FUZZAPI_PRE_SCRIPT: 분석기 시작 전에 런타임이나 종속성을 설치하는 스크립트

경고: Alpine Linux에서 스크립트를 실행하려면 먼저 chmod 명령을 사용하여 실행 권한을 설정해야 합니다. 예를 들어, script.py의 실행 권한을 모두에게 주려면 다음 명령을 사용합니다: chmod a+x script.py. 필요한 경우 실행 권한이 이미 설정된 script.py를 버전별로 관리할 수 있습니다.

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
  FUZZAPI_OVERRIDES_CMD: renew_token.py
  FUZZAPI_OVERRIDES_INTERVAL: 300

오버라이드 디버깅

기본적으로 오버라이드 명령의 출력은 숨겨집니다. 오버라이드 명령이 비정상 종료 코드를 반환하면 해당 명령은 작업 출력의 일부로 표시됩니다. 선택적으로 FUZZAPI_OVERRIDES_CMD_VERBOSE 변수를 아무 값이나 설정하여 오버라이드 명령 출력을 생성될 때 표시할 수 있습니다. 이는 오버라이드 스크립트를 테스트할 때 유용하지만, 테스트를 느리게 만들 수 있으므로 테스트 후에 비활성화해야 합니다.

스크립트에서 로그 메시지를 작성하여 작업 완료 또는 실패 시 수집되는 로그 파일에 메시지를 남길 수도 있습니다. 로그 파일은 특정 위치에 생성되고 특정한 명명규칙을 따라야 합니다.

오버라이드 스크립트에 기본 로깅을 추가하는 것은 작업에서 예상치 못한 방식으로 스크립트가 실패할 경우 유용합니다. 이 로그 파일은 작업의 아티팩트로 자동으로 포함되어 작업이 완료된 후에 다운로드할 수 있습니다.

우리의 예시를 따라 FUZZAPI_OVERRIDES_CMDrenew_token.py를 제공하였습니다. 스크립트에서 다음 두 가지를 주목하세요.

  • 로그 파일은 CI_PROJECT_DIR 환경 변수에서 저장됩니다.
  • 로그 파일 이름은 gl-*.log와 일치해야 합니다.
#!/usr/bin/env python

# 오버라이드 명령의 예시

# 오버라이드 명령을 사용하여 새로운 값을 사용할 overrides 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('FUZZAPI_OVERRIDES_FILE', 'api-fuzzing-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("오버라이드 파일이 업데이트되었습니다")

# 끝

오버라이드 명령 예시에서 파이썬 스크립트는 backoff 라이브러리에 의존합니다. 파이썬 스크립트를 실행하기 전에 해당 라이브러리가 설치되어 있는지 확인하려면 FUZZAPI_PRE_SCRIPT를 오버라이드 명령의 종속성을 설치하는 스크립트로 설정하십시오.

예를 들어, 다음 스크립트 user-pre-scan-set-up.sh:

#!/bin/bash

# user-pre-scan-set-up.sh
# python 종속성을 설치합니다

echo "**** 파이썬 종속성 설치 ****"

python3 -m ensurepip
pip3 install --no-cache --upgrade \
    pip \
    requests \
    backoff

echo "**** 파이썬 종속성 설치 완료 ****"

# end

설정을 업데이트하여 새로운 user-pre-scan-set-up.sh 스크립트를 FUZZAPI_PRE_SCRIPT로 설정하십시오. 예를 들어:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_PRE_SCRIPT: user-pre-scan-set-up.sh
  FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
  FUZZAPI_OVERRIDES_CMD: renew_token.py
  FUZZAPI_OVERRIDES_INTERVAL: 300

이전 예시에서 user-pre-scan-set-up.sh 스크립트를 사용하여 오버라이드 명령의 새로운 런타임이나 응용 프로그램을 설치하고 나중에 오버라이드 명령에서 사용할 수 있도록 할 수 있습니다.

제외 경로

API를 테스트할 때는 특정 경로를 제외하는 것이 유용할 수 있습니다. 예를 들어, 인증 서비스나 API의 이전 버전을 테스트에서 제외할 수 있습니다. 경로를 제외하려면 .gitlab-ci.yml 파일에서 FUZZAPI_EXCLUDE_PATHS CI/CD 변수를 사용하면 됩니다. 이 변수는 여러 개의 경로를 제외하려면 ; 문자를 사용하여 항목을 구분합니다. 제공된 경로에서는 단일 문자 와일드카드 ? 및 다중 문자 와일드카드 *를 사용할 수 있습니다.

제외된 경로가 올바르게 제외되었는지 확인하려면 작업 출력의 테스트된 작업(Tested Operations)제외된 작업(Excluded Operations) 부분을 확인하면 됩니다. 테스트된 작업에는 제외된 경로가 나열되어서는 안 됩니다.

2021-05-27 21:51:08 [INF] API Fuzzing: --[ Tested Operations ]-------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: --[ Excluded Operations ]-----------------------
2021-05-27 21:51:08 [INF] API Fuzzing: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------

경로 제외 예시

이 예에서는 /auth 리소스를 제외합니다. 이는 하위 리소스인 (/auth/child)를 제외하지 않습니다.

variables:
  FUZZAPI_EXCLUDE_PATHS: /auth

/auth 및 하위 리소스인 (/auth/child)를 제외하려면 와일드카드를 사용합니다.

variables:
  FUZZAPI_EXCLUDE_PATHS: /auth*

여러 개의 경로를 제외하려면 ; 문자를 사용합니다. 이 예에서는 /auth*/v1/*를 제외합니다.

variables:
  FUZZAPI_EXCLUDE_PATHS: /auth*;/v1/*

제외 매개변수

API를 테스트하는 동안 매개변수(쿼리 문자열, 헤더 또는 본문 요소)를 제외하려는 경우가 있을 수 있습니다. 이는 매개변수가 항상 실패를 유발하거나 테스트를 느리게 만들거나 기타 이유로 인해 필요할 수 있습니다. 매개변수를 제외하려면 다음 중 하나의 변수를 사용할 수 있습니다: FUZZAPI_EXCLUDE_PARAMETER_ENV 또는 FUZZAPI_EXCLUDE_PARAMETER_FILE.

FUZZAPI_EXCLUDE_PARAMETER_ENV는 제외된 매개변수를 포함하는 JSON 문자열을 제공합니다. JSON이 짧고 자주 변경되지 않는 경우 이 옵션이 좋은 선택입니다. 다른 옵션은 FUZZAPI_EXCLUDE_PARAMETER_FILE 변수를 사용하는 것입니다. 이 변수는 저장소에 체크인할 수 있는 파일 경로로 설정됩니다. 또는 다른 작업에서 아티팩트로 생성되거나 FUZZAPI_PRE_SCRIPT를 사용하여 미리 스크립트에서 런타임으로 생성될 수 있습니다.

JSON 문서를 사용하여 매개변수 제외

JSON 문서는 특정 속성을 사용하는 JSON 객체를 포함하며 스캔 프로세스 중에 특정 매개변수를 제외하도록합니다. 다음 속성을 제공하여 스캔 프로세스 중에 특정 매개변수를 제외할 수 있습니다.

  • headers: 특정 헤더를 제외하려면 이 속성을 사용합니다. 해당 속성 값은 제외할 헤더 이름의 배열입니다. 이름은 대소문자를 구분하지 않습니다.
  • cookies: 특정 쿠키를 제외하려면 이 속성을 사용합니다. 해당 속성 값은 제외할 쿠키 이름의 배열입니다. 이름은 대소문자를 구분합니다.
  • 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 속성의 값을 헤더 이름으로 구성된 배열로 설정하고 cookies 속성의 값을 쿠키 이름으로 구성된 배열로 설정하십시오. 예를 들어, JSON 문서는 다음과 같습니다.

{
  "headers": [ "Authorization" ],
  "cookies": [ "PHPSESSID", "csrftoken" ]
}

body-form 매개변수 제외

application/x-www-form-urlencoded를 사용하는 요청에서 password 필드를 제외하려면, body-form 속성의 값을 필드 이름으로 구성된 배열로 설정하십시오. 예를 들어, JSON 문서는 다음과 같습니다.

{
  "body-form":  [ "password" ]
}

제외 매개변수는 요청이 콘텐츠 유형 application/x-www-form-urlencoded를 사용할 때 body-form을 사용합니다.

JSON 경로를 사용하여 특정 JSON 노드 제외

루트 오브젝트의 schema 속성을 제외하려면, body-json 속성의 값을 JSON Path 표현식으로 구성된 배열로 설정하십시오.

JSON Path 표현식은 JSON 노드를 식별하기 위해 특별한 구문을 사용합니다: $는 JSON 문서의 루트를 나타내며, .는 현재 오브젝트를 나타냅니다 (우리의 경우 루트 오브젝트). 그리고 schema는 속성 이름을 나타냅니다. 따라서 JSON 경로 표현식 $.schema는 루트 오브젝트의 schema 속성을 나타냅니다. 예를 들어, JSON 문서는 다음과 같습니다.

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

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

JSON 경로를 사용하여 여러 JSON 노드 제외

루트 레벨의 users 배열의 각 항목에서 password 속성을 제외하려면, body-json 속성의 값을 JSON Path 표현식으로 구성된 배열로 설정하십시오.

JSON Path 표현식은 $로 시작하여 루트 노드를 참조하고 .을 사용하여 현재 노드를 참조합니다. 그런 다음 users를 사용하여 속성을 참조하고, [] 문자를 사용하여 숫자를 인덱스로 제공하는 대신 인덱스를 *로 지정합니다. 인덱스 참조 후, 배열에서 선택한 임의의 인덱스를 나타내는 .을 사용하고, password라는 속성 이름 앞에 구분하여 사용합니다.

예를 들어, JSON 문서는 다음과 같습니다.

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

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

XML 속성 제외

루트 엘리먼트 credentials에서 isEnabled라는 이름의 속성을 제외하려면, body-xml 속성의 값을 XPath 표현식으로 구성된 배열로 설정하십시오.

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 노드 제외

credentials 루트 노드에 포함되며 네임스페이스 s에 정의된 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 문서를 제공하려면 변수 FUZZAPI_EXCLUDE_PARAMETER_ENV에 JSON 문자열을 설정하세요. 다음 예에서 .gitlab-ci.yml에서 FUZZAPI_EXCLUDE_PARAMETER_ENV 변수는 JSON 문자열로 설정됩니다:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_EXCLUDE_PARAMETER_ENV: '{ "headers": [ "Upgrade-Insecure-Requests" ] }'

파일 사용

제외 JSON 문서를 제공하려면 변수 FUZZAPI_EXCLUDE_PARAMETER_FILE에 JSON 파일 경로를 설정하세요. 파일 경로는 작업의 현재 작업 디렉토리를 기준으로 상대적인 경로여야 합니다. 다음 예에서 .gitlab-ci.yml 파일에서 FUZZAPI_EXCLUDE_PARAMETER_FILE 변수는 JSON 파일 경로로 설정됩니다:

stages:
     - fuzz

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

variables:
  FUZZAPI_PROFILE: Quick
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_TARGET_URL: http://test-deployment/
  FUZZAPI_EXCLUDE_PARAMETER_FILE: api-fuzzing-exclude-parameters.json

api-fuzzing-exclude-parameters.json제외 매개변수 문서 구조를 따르는 JSON 문서입니다.

URL 제외

경로별로 제외하는 대신, FUZZAPI_EXCLUDE_URLS CI/CD 변수를 사용하여 URL의 다른 구성 요소로 필터링할 수도 있습니다. 이 변수는 .gitlab-ci.yml 파일에서 설정할 수 있습니다. 변수는 쉼표(,)로 구분된 여러 값들을 저장할 수 있습니다. 각 값은 정규 표현식입니다. 각 항목이 정규 표현식이기 때문에 .*과 같은 항목은 모든 것과 일치하는 정규 표현식이므로 모든 URL을 제외합니다.

작업 출력에서 FUZZAPI_EXCLUDE_URLS로 제공된 정규 표현식과 일치하는 URL이 있는지 확인할 수 있습니다. 일치하는 동작은 제외된 동작(Excluded Operations) 섹션에 나열됩니다. 제외된 동작(Excluded Operations)에 나열된 동작은 테스트된 동작(Tested Operations) 섹션에 나열되어서는 안 됩니다. 예를 들어, 작업 출력의 다음 부분: plaintext 2021-05-27 21:51:08 [INF] API Fuzzing: --[ Tested Operations ]------------------------- 2021-05-27 21:51:08 [INF] API Fuzzing: 201 POST http://target:7777/api/users CREATED 2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------ 2021-05-27 21:51:08 [INF] API Fuzzing: --[ Excluded Operations ]----------------------- 2021-05-27 21:51:08 [INF] API Fuzzing: GET http://target:7777/api/messages 2021-05-27 21:51:08 [INF] API Fuzzing: POST http://target:7777/api/messages 2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------

참고: FUZZAPI_EXCLUDE_URLS의 각 값은 정규 표현식입니다. ., *, $와 같은 문자는 정규 표현식에서 특별한 의미를 가지고 있습니다.

예시

URL 및 하위 리소스 제외

다음 예시에서는 URL http://target/api/auth와 해당 하위 리소스를 제외합니다. ```yaml stages: - fuzz

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

variables: FUZZAPI_TARGET_URL: http://target/ FUZZAPI_OPENAPI: test-api-specification.json FUZZAPI_EXCLUDE_URLS: http://target/api/auth ```

두 개의 URL 제외 및 해당 하위 리소스 허용

http://target/api/buyhttp://target/api/sell URL을 제외하면서 하위 리소스를 스캔할 수 있도록 허용하려면, 예를 들어 http://target/api/buy/toyhttp://target/api/sell/chair와 같은 하위 리소스를 스캔할 수 있습니다. 여기서는 두 개의 정규 표현식을 사용하여 값 http://target/api/buy/$,http://target/api/sell/$을 사용합니다. 각각의 정규 표현식은 , 문자로 구분되므로 이 값에는 http://target/api/buy$http://target/api/sell$이 포함되어 있습니다. 각 정규 표현식에서 끝에 있는 $ 문자는 일치하는 URL의 끝을 가리킵니다.

stages:
  - fuzz

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

variables:
  FUZZAPI_TARGET_URL: http://target/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_EXCLUDE_URLS: http://target/api/buy/$,http://target/api/sell/$

두 개의 URL 및 해당 하위 리소스 제외

http://target/api/buyhttp://target/api/sell, 그리고 그 하위 리소스들을 제외합니다. 여러 URL을 제공하려면 , 문자를 사용합니다. ```yaml stages: - fuzz

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

variables: FUZZAPI_TARGET_URL: http://target/ FUZZAPI_OPENAPI: test-api-specification.json FUZZAPI_EXCLUDE_URLS: http://target/api/buy,http://target/api/sell ```

정규 표현식을 사용하여 URL 제외

정확히 https://target/api/v1/user/createhttps://target/api/v2/user/create 또는 다른 버전(v3, v4 등)을 제외하려면 https://target/api/v.*/user/create$를 사용할 수 있습니다. 이전의 정규 표현식에서:

  • .는 어떤 문자든지 나타냅니다.
  • *는 0번 이상 나타남을 나타냅니다.
  • $는 URL이 그 위치에서 끝나야 함을 나타냅니다.
stages:
  - fuzz

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

variables:
  FUZZAPI_TARGET_URL: http://target/
  FUZZAPI_OPENAPI: test-api-specification.json
  FUZZAPI_EXCLUDE_URLS: https://target/api/v.*/user/create$

헤더 퍼징

많은 기술 스택에서 많은 거짓 양성이 발생하기 때문에 헤더 퍼징은 기본적으로 비활성화되어 있습니다. 헤더 퍼징을 활성화하려면 퍼징에 포함할 헤더 목록을 지정해야 합니다.

기본 구성 파일의 각 프로필에는 GeneralFuzzingCheck에 대한 항목이 있습니다. 이 체크는 헤더 퍼징을 수행합니다. Configuration 섹션에서 HeaderFuzzingHeaders 설정을 변경하여 헤더 퍼징을 활성화해야 합니다.

다음 코드는 헤더 퍼징이 비활성화된 Quick-10 프로필의 기본 구성을 보여줍니다:

- Name: Quick-10
  DefaultProfile: Empty
  Routes:
  - Route: *Route0
    Checks:
    - Name: FormBodyFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: false
        Headers:
    - Name: JsonFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
    - Name: XmlFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true

HeaderFuzzing는 헤더 퍼징을 켜거나 끄는 부울 값입니다. 기본 설정은 끄기인 false입니다. 헤더 퍼징을 켜려면 이 설정을 true로 변경하세요:

    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: true
        Headers:

Headers는 퍼징할 헤더의 목록입니다. 목록에 나열된 헤더만 퍼집니다. API에서 사용하는 헤더를 퍼징하려면 - Name: HeaderName 구문을 사용하여 해당 헤더에 대한 항목을 추가하세요. 예를 들어 사용자 지정 헤더 X-Custom를 퍼징하려면 - Name: X-Custom을 추가하세요:

    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: true
        Headers:
          - Name: X-Custom

이제 X-Custom 헤더를 퍼징하는 구성이 준비되었습니다. 추가 헤더를 나열하려면 동일한 표기법을 사용하세요:

    - Name: GeneralFuzzingCheck
      Configuration:
        FuzzingCount: 10
        UnicodeFuzzing: true
        HeaderFuzzing: true
        Headers:
          - Name: X-Custom
          - Name: X-AnotherHeader

필요한 경우 각 프로필에 대해 이러한 구성을 반복하세요.