성능 튜닝 및 테스트 속도
API 보안 테스트와 같은 동적 분석 테스트를 수행하는 보안 도구는 실행 중인 응용 프로그램의 인스턴스에 요청을 보내어 테스트를 수행합니다. 요청은 응용 프로그램에 존재할 수 있는 특정 취약점을 테스트하기 위해 설계됩니다. 동적 분석 테스트의 속도는 다음에 따라 달라집니다.
- 우리의 도구가 응용 프로그램에 초당 보낼 수 있는 요청의 수
- 응용 프로그램이 요청에 응답하는 속도
- 응용 프로그램을 테스트하기 위해 보내어야 하는 요청의 수
- 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초의 평균 응답 시간은 이 특정 작업이 테스트하는 데 오랜 시간이 걸린다는 초기 지표로 볼 수 있습니다. 더 나아가 응답 바디 크기가 상당히 크다는 것을 알 수 있습니다. 큰 바디 크기가 주요 문제이며, 각 요청에서 그만큼의 데이터를 전송하는 데 가장 많은 시간이 소요됩니다.
이 문제에 대해 팀은 다음을 결정할 수 있습니다.
- API 보안 테스트가 수행하는 작업을 병렬로 처리할 수 있도록 더 많은 vCPU가 있는 실행자를 사용합니다. 이렇게 하면 테스트 시간이 줄어들지만, 테스트 시간을 10분 미만으로 단축하는 것은 특히 이 작업이 테스트하는 데 걸리는 시간으로 인해 고사하다는 문제가 있을 수 있습니다. 더 큰 실행자는 비용이 더 많이 들지만, 작업 실행이 더 빨라지면 적은 분만 지불하게 됩니다.
- 이 작업을 제외하여 API 보안 테스트에서 제외합니다. 이것은 가장 간단한 방법이지만 보안 테스트 범위에 결함이 생길 수 있습니다.
- 기능 브랜치 API 보안 테스트에서 이 작업을 제외하고, 기본 브랜치 테스트에서는 포함.
- API 보안 테스트를 여러 작업으로 분할합니다.
가능한 해결 방법은 팀의 요구 사항이 5-7분 정도인 경우를 가정하면, 이러한 해결 방법을 조합하여 테스트 시간을 수용할 수 있도록 하는 것입니다.
성능 문제 해결
다음 섹션에서는 API 보안 테스트의 성능 문제를 해결하기 위한 여러 옵션에 대해 설명합니다.
더 큰 실행자 사용
API 보안 테스트에서 더 큰 실행자를 사용하는 것은 가장 쉬운 성능 향상 방법 중 하나입니다. 이 표는 Java Spring Boot REST API의 벤치마킹 중 수집된 통계를 보여줍니다. 이 벤치마킹에서 대상 및 API 보안 테스트가 단일 실행자 인스턴스를 공유합니다.
호스티드 실행자의 Linux 태그 | 초당 요청 수 |
---|---|
saas-linux-small-amd64 (기본값)
| 255 |
saas-linux-medium-amd64
| 400 |
이 표에서 보듯이 실행자 크기와 vCPU 수를 늘리면 테스트 속도/성능에 큰 영향을 미칠 수 있습니다.
다음은 Linux에서 중간 SaaS 실행자를 사용하는 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] <Peach.Web.Core.Services.WebRunnerMachine> 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
테스트에서 작업을 제외하는 것은 몇 가지 취약점을 감지하지 못하게 할 수 있습니다.
테스트를 여러 작업으로 분할하기
테스트를 여러 작업으로 분할하는 것은 API 보안 테스트에서 APISEC_EXCLUDE_PATHS
와 APISEC_EXCLUDE_URLS
사용을 통해 지원됩니다. 테스트를 분할할 때는 dast_api
작업을 비활성화하고, 식별 가능한 이름을 가진 두 개의 작업으로 대체하는 것이 좋은 패턴입니다. 이 예에서는 두 개의 작업이 있고, 각 작업은 API의 버전을 테스트하므로 이름이 그에 해당합니다. 그러나 이 기술은 API의 버전뿐만 아니라 다른 상황에도 적용될 수 있습니다.
APISEC_v1
및 APISEC_v2
작업에 사용하는 규칙은 API 보안 테스트 템플릿에서 복사되었습니다.
# 주요 dast_api 작업 비활성화
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 보안 테스트 작업을 실행하고 작업 콘솔 출력을 확인합니다. 테스트의 끝에 포함된 작업 및 제외된 작업 목록이 포함됩니다.
# 다른 이름을 가진 두 개의 작업을 만들기 위해 주요 작업 비활성화
api_security:
rules:
- if: $CI_COMMIT_BRANCH
when: never
# 기능 브랜치 작업에 대한 API 보안 테스트, /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
# 기본 브랜치 (이 경우 main)를 위한 API 보안 테스트
# 긴 작업을 포함
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