성능 튜닝 및 테스트 속도
GitLab v19.1API 보안 테스팅과 같이 동적 분석 테스팅을 수행하는 보안 도구는 실행 중인 애플리케이션 인스턴스에 요청을 보내 테스팅을 수행합니다. 이 성능 가이드의 조언을 따른 후에도 API 보안 테스팅 작업이 예상보다 오래 걸리는 경우 추가 지원을 위해 지원팀에 문의하세요.
API 보안 테스팅과 같이 동적 분석 테스팅을 수행하는 보안 도구는 실행 중인 애플리케이션 인스턴스에 요청을 보내 테스팅을 수행합니다. 요청은 애플리케이션에 존재할 수 있는 특정 취약점을 테스트하도록 설계되어 있습니다. 동적 분석 테스트의 속도는 다음에 따라 달라집니다:
- GitLab 도구가 애플리케이션으로 초당 얼마나 많은 요청을 보낼 수 있는지
- 애플리케이션이 얼마나 빠르게 요청에 응답하는지
- 애플리케이션을 테스트하기 위해 얼마나 많은 요청을 보내야 하는지
API가 구성된 작업의 수
- 각 작업의 필드 수 (JSON 본문, 헤더, 쿼리 문자열, 쿠키 등)
이 성능 가이드의 조언을 따른 후에도 API 보안 테스팅 작업이 예상보다 오래 걸리는 경우 추가 지원을 위해 지원팀에 문의하세요.
성능 문제 진단#
성능 문제를 해결하는 첫 번째 단계는 예상보다 느린 테스트 시간에 기여하는 원인을 이해하는 것입니다. 일반적으로 보고되는 문제는 다음과 같습니다:
- API 보안 테스팅이 낮은 vCPU 러너에서 실행 중
- 애플리케이션이 느린/단일 CPU 인스턴스에 배포되어 테스팅 부하를 처리하지 못함
- 애플리케이션에 전체 테스트 속도에 영향을 미치는 느린 작업 포함 (> 1/2초)
- 애플리케이션에 많은 양의 데이터를 반환하는 작업 포함 (> 500K+)
- 애플리케이션에 많은 수의 작업 포함 (> 40)
전체 테스트 속도에 영향을 미치는 느린 작업이 있는 경우 (> 1/2초)#
API 보안 테스팅 작업 출력에는 테스트 속도, 작업 응답 시간 및 요약 정보에 대한 유용한 정보가 포함됩니다. 다음 샘플 출력은 성능 문제를 추적하는 데 요약 출력을 활용하는 방법을 보여줍니다:
API SECURITY: Loaded 10 operations from: assets/har-large-response/large_responses.har
API SECURITY:
API SECURITY: Testing operation [1/10]: 'GET http://target:7777/api/large_response_json'.
API SECURITY: - Parameters: (Headers: 4, Query: 0, Body: 0)
API SECURITY: - Request body size: 0 Bytes (0 bytes)
API SECURITY:
API SECURITY: Finished testing operation 'GET http://target:7777/api/large_response_json'.
API SECURITY: - Excluded Parameters: (Headers: 0, Query: 0, Body: 0)
API SECURITY: - Performed 767 requests
API SECURITY: - Average response body size: 130 MB
API SECURITY: - Average call time: 2 seconds and 82.69 milliseconds (2.082693 seconds)
API SECURITY: - Time to complete: 14 minutes, 8 seconds and 788.36 milliseconds (848.788358 seconds)
작업 콘솔 출력 스니펫은 발견된 작업 수(10개)로 시작합니다. 다음으로, 특정 작업에서 테스팅이 시작되었고 완료 요약이 있음을 알립니다. 요약은 이 작업과 관련 필드를 완전히 테스트하는 데 API 보안 테스팅이 767개의 요청을 사용했음을 보여줍니다. 또한 작업의 평균 응답 시간이 2초였고 완료하는 데 14분이 걸렸음을 보여줍니다.
평균 응답 시간 2초는 이 특정 작업이 테스트하는 데 오랜 시간이 걸린다는 좋은 초기 지표입니다. 요약은 또한 긴 응답 시간을 유발하는 큰 응답 본문 크기를 보여줍니다. 각 요청의 응답 시간 대부분이 응답 본문 데이터를 전송하는 데 소요됩니다.
이 문제에 대해 팀은 다음을 결정할 수 있습니다:
-
vCPU가 더 많은 러너를 사용하여 API 보안 테스팅이 수행하는 작업을 병렬화합니다. 이는 테스트 시간을 줄이는 데 도움이 되지만, 작업 테스트에 시간이 얼마나 걸리는지를 감안할 때 더 큰 CPU 머신으로 이전하지 않고는 10분 이하로 줄이는 것이 여전히 어려울 수 있습니다. 더 큰 러너는 더 비싸지만, 작업 실행이 더 빨라지면 소비하는 분도 줄어듭니다.
-
이 작업을 API 보안 테스팅에서 제외합니다. 가장 간단한 방법이지만 보안 테스트 커버리지에 공백이 생기는 단점이 있습니다.
팀의 요구 사항이 5-7분 범위라고 가정하면 가장 좋은 해결책은 이러한 방법의 조합을 사용하여 허용 가능한 테스트 시간에 도달하는 것입니다.
성능 문제 해결#
다음 섹션은 API 보안 테스팅의 성능 문제를 해결하기 위한 다양한 옵션을 문서화합니다:
더 큰 러너 사용#
API 보안 테스팅과 함께 더 큰 러너를 사용하면 가장 쉽게 성능을 향상시킬 수 있습니다. 이 표는 Java Spring Boot REST API의 벤치마킹 중 수집된 통계를 보여줍니다. 이 벤치마크에서 타겟과 API 보안 테스팅은 단일 러너 인스턴스를 공유합니다.
| Linux의 호스팅 러너 태그 | 초당 요청 수 |
|---|---|
| saas-linux-small-amd64 (기본) | 255 |
| saas-linux-medium-amd64 | 400 |
이 표는 러너와 vCPU 크기를 늘리면 테스트 속도/성능에 큰 영향을 미칠 수 있음을 보여줍니다.
다음은 Linux에서 중간 GitLab 호스팅 러너를 사용하기 위해 tags 섹션을 추가하는 API 보안 테스팅의 작업 정의 예시입니다. 이 작업은 API 보안 테스팅 템플릿을 통해 포함된 작업 정의를 확장합니다.
api_security:
tags:
- saas-linux-medium-amd64
gl-api-security-scanner.log 파일에서 문자열 Starting work item processor를 검색하여 보고된 최대 DOP(병렬 처리 정도)를 검사할 수 있습니다. 최대 DOP는 러너에 할당된 vCPU 수보다 크거나 같아야 합니다. 문제를 식별할 수 없는 경우 지원팀에 티켓을 열어 도움을 받으세요.
로그 항목 예시:
17:00:01.084 [INF] Starting work item processor with 4 max DOP
느린 작업 제외#
느린 작업이 한두 개인 경우 팀은 해당 작업의 테스트를 건너뛰기로 결정할 수 있습니다. 작업 제외는 APISEC_EXCLUDE_PATHS 구성 변수를 사용하여 이 섹션에서 설명한 대로 수행됩니다.
이 예시는 많은 양의 데이터를 반환하는 작업을 보여줍니다. 작업은 GET http://target:7777/api/large_response_json입니다. 제외하려면 작업 URL /api/large_response_json의 경로 부분으로 APISEC_EXCLUDE_PATHS 구성 변수를 제공합니다.
작업이 제외되었는지 확인하려면 API 보안 테스팅 작업을 실행하고 작업 콘솔 출력을 검토합니다. 테스트가 끝날 때 포함된 작업과 제외된 작업의 목록이 포함되어 있습니다.
api_security:
variables:
APISEC_EXCLUDE_PATHS: /api/large_response_json
테스트에서 작업을 제외하면 일부 취약점이 탐지되지 않을 수 있습니다.
테스트를 여러 작업으로 분할#
테스트를 여러 작업으로 분할하는 것은 APISEC_EXCLUDE_PATHS 및 APISEC_EXCLUDE_URLS를 통해 API 보안 테스팅에서 지원됩니다. 테스트를 분할할 때 좋은 패턴은 dast_api 작업을 비활성화하고 식별 이름이 있는 두 작업으로 교체하는 것입니다. 이 예시는 두 작업을 보여줍니다. 각 작업은 이름에서 알 수 있듯이 API 버전을 테스트합니다. 그러나 이 기술은 API 버전에만 국한되지 않고 모든 상황에 적용될 수 있습니다.
APISEC_v1 및 APISEC_v2 작업에 사용된 규칙은 API 보안 테스팅 템플릿에서 복사됩니다.
# Disable the main dast_api job
api_security:
rules:
- if: $CI_COMMIT_BRANCH
when: never
APISEC_v1:
extends: dast_api
variables:
APISEC_EXCLUDE_PATHS: /api/v1/**
rules:
- if: $APISEC_DISABLED == 'true' || $APISEC_DISABLED == '1'
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
$CI_GITLAB_FIPS_MODE == "true"
variables:
APISEC_IMAGE_SUFFIX: "-fips"
- if: $CI_COMMIT_BRANCH
APISEC_v2:
variables:
APISEC_EXCLUDE_PATHS: /api/v2/**
rules:
- if: $APISEC_DISABLED == 'true' || $APISEC_DISABLED == '1'
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
$CI_GITLAB_FIPS_MODE == "true"
variables:
APISEC_IMAGE_SUFFIX: "-fips"
- if: $CI_COMMIT_BRANCH
피처 브랜치가 아닌 기본 브랜치에서 작업 제외#
느린 작업이 한두 개인 경우 팀은 해당 작업의 테스트를 건너뛰거나 피처 브랜치 테스트에서는 제외하되 기본 브랜치 테스트에는 포함하기로 결정할 수 있습니다. 작업 제외는 APISEC_EXCLUDE_PATHS 구성 변수를 사용하여 이 섹션에서 설명한 대로 수행됩니다.
이 예시는 많은 양의 데이터를 반환하는 작업을 보여줍니다. 작업은 GET http://target:7777/api/large_response_json입니다. 제외하려면 작업 URL /api/large_response_json의 경로 부분으로 APISEC_EXCLUDE_PATHS 구성 변수를 제공합니다. 구성은 메인 dast_api 작업을 비활성화하고 두 개의 새 작업 APISEC_main과 APISEC_branch를 생성합니다. APISEC_branch는 긴 작업을 제외하고 기본 브랜치가 아닌 브랜치(예: 피처 브랜치)에서만 실행되도록 설정됩니다. APISEC_main 브랜치는 기본 브랜치(main)에서만 실행되도록 설정됩니다. APISEC_branch 작업은 더 빠르게 실행되어 빠른 개발 주기를 허용하는 반면, 기본 브랜치 빌드에서만 실행되는 APISEC_main 작업은 실행하는 데 더 오래 걸립니다.
작업이 제외되었는지 확인하려면 API 보안 테스팅 작업을 실행하고 작업 콘솔 출력을 검토합니다. 테스트가 끝날 때 포함된 작업과 제외된 작업의 목록이 포함되어 있습니다.
# Disable the main job so you can create two jobs with
# different names
api_security:
rules:
- if: $CI_COMMIT_BRANCH
when: never
# API security testing for feature branch work, excludes /api/large_response_json
APISEC_branch:
extends: dast_api
variables:
APISEC_EXCLUDE_PATHS: /api/large_response_json
rules:
- if: $APISEC_DISABLED == 'true' || $APISEC_DISABLED == '1'
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
$CI_GITLAB_FIPS_MODE == "true"
variables:
APISEC_IMAGE_SUFFIX: "-fips"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: never
- if: $CI_COMMIT_BRANCH
# API security testing for default branch (main in this case)
# Includes the long running operations
APISEC_main:
extends: dast_api
rules:
- if: $APISEC_DISABLED == 'true' || $APISEC_DISABLED == '1'
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $APISEC_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
$CI_GITLAB_FIPS_MODE == "true"
variables:
APISEC_IMAGE_SUFFIX: "-fips"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH