분석기 설정 사용자 지정
API 퍼징 동작은 CI/CD 변수를 통해 변경할 수 있습니다.
API 퍼징 구성 파일은 리포지토리의 .gitlab
디렉토리에 있어야 합니다.
경고:
GitLab 보안 스캐닝 도구의 모든 사용자 지정은 기본 브랜치에 이러한 변경 사항을 병합하기 전에 병합 요청에서 테스트해야 합니다. 그렇게 하지 않으면 예기치 않은 결과가 발생할 수 있으며, 많은 수의 허위 긍정이 포함될 수 있습니다.
인증
인증은 인증 토큰을 헤더 또는 쿠키로 제공하여 처리됩니다. 인증 흐름을 수행하거나 토큰을 계산하는 스크립트를 제공할 수 있습니다.
HTTP 기본 인증
HTTP 기본 인증은 HTTP 프로토콜에 내장된 인증 방법으로, 전송 계층 보안(TLS)과 함께 사용됩니다.
비밀번호에 대해 CI/CD 변수를 생성하는 것을 권장합니다 (예: TEST_API_PASSWORD
) 그리고 이를 마스킹하도록 설정합니다. GitLab 프로젝트 페이지의 Settings > CI/CD의 Variables 섹션에서 CI/CD 변수를 생성할 수 있습니다. 마스킹된 변수의 제한 사항 때문에 비밀번호를 변수로 추가하기 전에 Base64로 인코딩해야 합니다.
마지막으로, 아래와 같이 두 개의 CI/CD 변수를 .gitlab-ci.yml
파일에 추가하세요:
-
FUZZAPI_HTTP_USERNAME
: 인증을 위한 사용자 이름입니다. -
FUZZAPI_HTTP_PASSWORD_BASE64
: 인증을 위한 Base64로 인코딩된 비밀번호입니다.
stages:
- fuzz
include:
- template: API-Fuzzing.gitlab-ci.yml
variables:
FUZZAPI_PROFILE: Quick-10
FUZZAPI_HAR: test-api-recording.har
FUZZAPI_TARGET_URL: http://test-deployment/
FUZZAPI_HTTP_USERNAME: testuser
FUZZAPI_HTTP_PASSWORD_BASE64: $TEST_API_PASSWORD
원시 비밀번호
비밀번호를 Base64로 인코딩하고 싶지 않거나(GitLab 15.3 이하를 사용하는 경우) FUZZAPI_HTTP_PASSWORD
를 사용하여 원시 비밀번호를 제공할 수 있습니다.
베어러 토큰
베어러 토큰은 OAuth2 및 JSON Web Tokens(JWT)를 포함한 여러 인증 메커니즘에서 사용됩니다. 베어러 토큰은 Authorization
HTTP 헤더를 사용하여 전송됩니다. API 퍼징과 함께 베어러 토큰을 사용하려면 다음 중 하나가 필요합니다:
- 만료되지 않는 토큰
- 테스트 기간 동안 지속되는 토큰을 생성하는 방법
- API 퍼징이 호출할 수 있는 토큰을 생성하는 Python 스크립트
토큰이 만료되지 않음
베어러 토큰이 만료되지 않는 경우 FUZZAPI_OVERRIDES_ENV
변수를 사용하여 제공하세요. 이 변수의 내용은 API 퍼징의 아웃고잉 HTTP 요청에 추가할 헤더 및 쿠키를 제공하는 JSON 스니펫입니다.
FUZZAPI_OVERRIDES_ENV
와 함께 베어러 토큰을 제공하려면 다음 단계를 따르세요:
-
CI/CD 변수를 생성합니다, 예를 들어
TEST_API_BEARERAUTH
, 값은{"headers":{"Authorization":"Bearer dXNlcm5hbWU6cGFzc3dvcmQ="}}
(자신의 토큰으로 대체)로 설정합니다. GitLab 프로젝트 페이지의 Settings > CI/CD의 Variables 섹션에서 CI/CD 변수를 생성할 수 있습니다. -
.gitlab-ci.yml
파일에서FUZZAPI_OVERRIDES_ENV
를 방금 생성한 변수로 설정합니다:stages: - fuzz include: - template: API-Fuzzing.gitlab-ci.yml variables: FUZZAPI_PROFILE: Quick-10 FUZZAPI_OPENAPI: test-api-specification.json FUZZAPI_TARGET_URL: http://test-deployment/ FUZZAPI_OVERRIDES_ENV: $TEST_API_BEARERAUTH
-
인증이 작동하는지 확인하기 위해 API 퍼징 테스트를 실행하고 퍼징 로그 및 테스트 API의 애플리케이션 로그를 검토하세요. 오버라이드 명령에 대한 추가 정보는 오버라이드 섹션을 참조하세요.
테스트 런타임에 생성된 토큰
베어러 토큰을 생성해야 하고 테스트 중 만료되지 않는 경우, 이 토큰을 포함하는 파일을 사용하여 API 퍼징에 제공할 수 있습니다. 이전 단계와 작업 또는 API 퍼징 작업의 일부가 이 파일을 생성할 수 있습니다.
API 퍼징은 다음 구조의 JSON 파일을 받을 것으로 예상합니다:
{
"headers" : {
"Authorization" : "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}
이 파일은 이전 단계에서 생성되어 FUZZAPI_OVERRIDES_FILE
CI/CD 변수를 통해 API 퍼징에 제공될 수 있습니다.
.gitlab-ci.yml
파일에서 FUZZAPI_OVERRIDES_FILE
을 설정하세요:
stages:
- fuzz
include:
- template: API-Fuzzing.gitlab-ci.yml
variables:
FUZZAPI_PROFILE: Quick
FUZZAPI_OPENAPI: test-api-specification.json
FUZZAPI_TARGET_URL: http://test-deployment/
FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
인증이 작동하는지 확인하려면 API 퍼징 테스트를 실행하고 퍼징 로그와 테스트 API의 애플리케이션 로그를 검토하세요.
토큰이 짧은 만료를 가질 때
베어러 토큰을 생성해야 하고 스캔 완료 전에 만료되는 경우, 지정된 간격으로 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
을 제공합니다.
이 파일에는 특정 수의 테스트를 수행하는 여러 테스트 프로필이 포함되어 있습니다. 각 프로필의 런타임은 테스트 수가 증가함에 따라 증가합니다.
프로필 | 매개변수당 퍼징 테스트 |
---|---|
Quick-10 | 10 |
Medium-20 | 20 |
Medium-50 | 50 |
Long-100 | 100 |
오버라이드
API Fuzzing은 요청에서 특정 항목을 추가하거나 오버라이드하는 방법을 제공합니다. 예를 들어:
- 헤더
- 쿠키
- 쿼리 문자열
- 폼 데이터
- 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을 파일로 제공하려면 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
에 의해 제공된 스크립트는 분석기가 시작되기 전에 한 번 실행됩니다.
참고:
높은 권한이 필요한 작업을 수행할 때는 sudo
명령을 사용하세요.
예: sudo apk add nodejs
.
Alpine Linux 패키지 설치에 대한 정보는 Alpine Linux 패키지 관리 페이지를 참조하세요.
정확한 작동을 위해 세 가지 CI/CD 변수를 제공해야 합니다:
-
FUZZAPI_OVERRIDES_FILE
: 제공된 명령에 의해 생성된 파일. -
FUZZAPI_OVERRIDES_CMD
: 주기적으로 오버라이드 JSON 파일 생성을 책임지는 명령. -
FUZZAPI_OVERRIDES_INTERVAL
: 명령을 실행할 간격(초).
선택적으로:
-
FUZZAPI_PRE_SCRIPT
: 분석기가 시작되기 전에 런타임이나 종속성을 설치하는 스크립트.
경고:
Alpine Linux에서 스크립트를 실행하려면 먼저 chmod
명령을 사용하여 실행 권한을 설정해야 합니다. 예를 들어, script.py
의 모든 사용자에 대한 실행 권한을 설정하려면 다음 명령을 사용하세요: sudo 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
디버깅 오버라이드
기본적으로 오버라이드 명령의 출력은 숨겨져 있습니다. 오버라이드 명령이 0이 아닌 종료 코드를 반환하면 해당 명령이 작업 출력의 일부로 표시됩니다. 선택적으로, FUZZAPI_OVERRIDES_CMD_VERBOSE
변수를 임의의 값으로 설정하면 생성되는 대로 오버라이드 명령 출력을 표시할 수 있습니다. 이는 오버라이드 스크립트를 테스트할 때 유용하지만, 이후에는 비활성화하는 것이 좋습니다. 왜냐하면 테스트 속도를 저하시킬 수 있기 때문입니다.
스크립트에서 메시지를 로그 파일로 작성하는 것도 가능하며, 이는 작업이 완료되거나 실패할 때 수집됩니다. 로그 파일은 특정 위치에 생성되어야 하며 명명 규칙을 따라야 합니다.
오버라이드 스크립트에 기본적인 로깅을 추가하는 것이 유용한데, 이는 스크립트가 일반적인 작업 실행 중에 예기치 않게 실패할 경우에 대비하기 위함입니다. 로그 파일은 작업의 아티팩트로 자동으로 포함되므로, 작업이 완료된 후 다운로드할 수 있습니다.
예를 들어, 우리는 환경 변수 FUZZAPI_OVERRIDES_CMD
에 renew_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('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("오버라이드 파일이 업데이트되었습니다.")
# 종료
오버라이드 명령 예에서, Python 스크립트는 backoff
라이브러리에 의존합니다. Python 스크립트를 실행하기 전에 라이브러리가 설치되도록 보장하기 위해, FUZZAPI_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 \
requests \
backoff
echo "**** Python 종속성 설치 완료 ****"
# 종료
구성을 업데이트하여 FUZZAPI_PRE_SCRIPT
를 새로운 user-pre-scan-set-up.sh
스크립트로 설정해야 합니다. 예를 들어:
stages:
- fuzz
include:
- template: API-Fuzzing.gitlab-ci.yml
variables:
FUZZAPI_PROFILE: Quick
FUZZAPI_OPENAPI: test-api-specification.json
FUZZAPI_TARGET_URL: http://test-deployment/
FUZZAPI_PRE_SCRIPT: user-pre-scan-set-up.sh
FUZZAPI_OVERRIDES_FILE: api-fuzzing-overrides.json
FUZZAPI_OVERRIDES_CMD: renew_token.py
FUZZAPI_OVERRIDES_INTERVAL: 300
이전 샘플에서는, 당신은 user-pre-scan-set-up.sh
스크립트를 사용하여 나중에 오버라이드 명령에서 사용할 수 있는 새로운 런타임이나 애플리케이션을 설치할 수도 있습니다.
제외 경로
API를 테스트할 때 특정 경로를 제외하는 것이 유용할 수 있습니다. 예를 들어, 인증 서비스나 이전 버전의 API 테스트를 제외할 수 있습니다. 경로를 제외하려면 FUZZAPI_EXCLUDE_PATHS
CI/CD 변수를 사용하세요. 이 변수는 .gitlab-ci.yml
파일에 지정됩니다. 여러 경로를 제외하려면 ;
문자로 항목을 구분합니다. 제공된 경로에서 단일 문자 와일드카드 ?
와 다중 문자 와일드카드 *
를 사용할 수 있습니다.
경로가 제외되었는지 확인하려면 작업 출력의 Tested Operations
와 Excluded Operations
부분을 검토하세요. Tested Operations
아래에 제외된 경로가 나열되지 않아야 합니다.
2021-05-27 21:51:08 [INF] API Fuzzing: --[ Tested Operations ]-------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: 201 POST http://target:7777/api/users CREATED
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------
2021-05-27 21:51:08 [INF] API Fuzzing: --[ Excluded Operations ]-----------------------
2021-05-27 21:51:08 [INF] API Fuzzing: GET http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: POST http://target:7777/api/messages
2021-05-27 21:51:08 [INF] API Fuzzing: ------------------------------------------------
경로 제외 예시
이 예시는 /auth
리소스를 제외합니다. 이는 자식 리소스(/auth/child
)를 제외하지 않습니다.
variables:
FUZZAPI_EXCLUDE_PATHS: /auth
/auth
와 자식 리소스(/auth/child
)를 제외하려면 와일드카드를 사용합니다.
variables:
FUZZAPI_EXCLUDE_PATHS: /auth*
여러 경로를 제외하려면 ;
문자를 사용할 수 있습니다. 이 예시에서는 /auth*
와 /v1/*
을 제외합니다.
variables:
FUZZAPI_EXCLUDE_PATHS: /auth*;/v1/*
제외할 매개변수
API를 테스트하는 동안 매개변수(쿼리 문자열, 헤더 또는 본문 요소)를 제외하고 싶을 수 있습니다. 이는 매개변수가 항상 실패를 유발하거나 테스트 속도를 저하시킬 수 있기 때문입니다. 매개변수를 제외하려면 다음 변수를 사용할 수 있습니다: FUZZAPI_EXCLUDE_PARAMETER_ENV
또는 FUZZAPI_EXCLUDE_PARAMETER_FILE
.
FUZZAPI_EXCLUDE_PARAMETER_ENV
는 제외할 매개변수를 포함하는 JSON 문자열을 제공합니다. JSON이 짧고 자주 변경되지 않는 경우에는 좋은 옵션입니다. 또 다른 옵션은 FUZZAPI_EXCLUDE_PARAMETER_FILE
변수로, 이 변수는 저장소에 체크인할 수 있는 파일 경로로 설정되어 있거나, 다른 작업에서 아티팩트로 생성되거나, FUZZAPI_PRE_SCRIPT
를 사용하여 런타임 중 생성될 수 있습니다.
JSON 문서를 사용하여 매개변수 제외하기
JSON 문서는 특정 속성을 사용하여 어떤 매개변수를 제외할지 식별하는 JSON 객체를 포함합니다. 스캔 과정에서 특정 매개변수를 제외하기 위해 다음 속성을 제공할 수 있습니다:
-
headers
: 특정 헤더를 제외하는 데 사용하는 속성입니다. 속성 값은 제외할 헤더 이름의 배열입니다. 이름은 대/소문자를 구분하지 않습니다. -
cookies
: 특정 쿠키를 제외하는 데 사용하는 속성 값입니다. 속성 값은 제외할 쿠키 이름의 배열입니다. 이름은 대/소문자를 구분합니다. -
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-REQUESTS
는 Upgrade-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[*].paswword" ]
으로 설정합니다.
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 표현식 [ "/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
이 옵니다. 이름에 :
문자가 포함되어 있음을 주목하세요. 이 문자는 네임스페이스를 노드 이름과 구분합니다.
네임스페이스 이름은 요청 본문의 일부인 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을 제외합니다. 이는 모든 것을 일치시키는 정규 표현식이기 때문입니다.
작업 출력에서 제공된 정규 표현식 중 어떤 것과 일치하는 URL이 있는지 확인할 수 있습니다. 일치하는 작업은 제외된 작업 섹션에 나열됩니다. 제외된 작업에 나열된 작업은 테스트된 작업 섹션에 나열되지 않아야 합니다. 예를 들어 작업 출력의 다음 부분:
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: ------------------------------------------------
예시
URL 및 자원 제외
다음 예시는 URL http://target/api/auth
와 그 하위 자원을 제외합니다.
stages:
- fuzz
include:
- template: API-Fuzzing.gitlab-ci.yml
variables:
FUZZAPI_TARGET_URL: http://target/
FUZZAPI_OPENAPI: test-api-specification.json
FUZZAPI_EXCLUDE_URLS: http://target/api/auth
두 개의 URL 제외 및 자원 허용
URL http://target/api/buy
와 http://target/api/sell
을 제외하되, 하위 자원을 스캔할 수 있도록 하려면, 예를 들어: http://target/api/buy/toy
또는 http://target/api/sell/chair
와 같이 사용할 수 있습니다. 이 값을 http://target/api/buy/$,http://target/api/sell/$
로 설정할 수 있습니다. 이 값은 두 개의 정규 표현식을 사용하며, 각 정규 표현식은 ,
문자로 구분됩니다. 따라서 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 및 하위 자원 제외
URL: http://target/api/buy
와 http://target/api/sell
, 그리고 그 하위 자원을 제외하려면, 여러 URL을 제공하기 위해 ,
문자를 다음과 같이 사용합니다:
stages:
- fuzz
include:
- template: API-Fuzzing.gitlab-ci.yml
variables:
FUZZAPI_TARGET_URL: http://target/
FUZZAPI_OPENAPI: test-api-specification.json
FUZZAPI_EXCLUDE_URLS: http://target/api/buy,http://target/api/sell
정규 표현식을 사용하여 URL 제외
정확히 https://target/api/v1/user/create
와 https://target/api/v2/user/create
또는 다른 버전(v3
, v4
등)을 제외하려면 https://target/api/v.*/user/create$
를 사용할 수 있습니다. 이전 정규 표현식에서:
-
.
는 임의의 문자를 나타냅니다. -
*
는 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
섹션에서 HeaderFuzzing
및 Headers
설정을 변경하여 헤더 퍼징을 활성화해야 합니다.
이 스니펫은 헤더 퍼징이 비활성화된 Quick-10
프로파일의 기본 구성을 보여줍니다:
- Name: Quick-10
DefaultProfile: Empty
Routes:
- Route: *Route0
Checks:
- Name: FormBodyFuzzingCheck
Configuration:
FuzzingCount: 10
UnicodeFuzzing: true
- Name: GeneralFuzzingCheck
Configuration:
FuzzingCount: 10
UnicodeFuzzing: true
HeaderFuzzing: false
Headers:
- Name: JsonFuzzingCheck
Configuration:
FuzzingCount: 10
UnicodeFuzzing: true
- Name: XmlFuzzingCheck
Configuration:
FuzzingCount: 10
UnicodeFuzzing: 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
필요한 만큼 각 프로파일에 대해 이 구성을 반복하십시오.