본문으로 건너뛰기

41. API 보안 테스팅: 실전 가이드

API 테스트의 핵심은 많은 요청을 보내는 일이 아니라, 한 요청이 어느 신뢰 경계를 넘는지 설명하는 일이다. 명시적 범위의 자기 서비스, 승인된 테스트 환경, CTF에서만 수행한다. 테스트 계정과 합성 데이터, 낮은 요청률을 사용하고 운영 사용자 데이터는 읽거나 바꾸지 않는다.

표면을 모델로 바꾸기

OpenAPI 문서, 라우팅 코드, 클라이언트 트래픽, GraphQL 스키마를 대조해 엔드포인트·메서드·인증 방식·객체 식별자·민감 필드를 표로 만든다. 문서에 없는 경로보다 중요한 것은 같은 객체가 여러 버전과 역할별 API에서 어떻게 표현되는지다. Burp Repeater, ZAP, curl은 도구일 뿐이며, 각각의 요청에는 테스트 계정과 기대 결과를 붙인다.

가장 먼저 인증과 인가를 분리한다. 토큰이 유효하다는 것과 그 토큰이 해당 객체를 읽을 권한이 있다는 것은 별개의 판정이다. 두 테스트 계정으로 동일한 리소스 ID를 요청해 수평 권한 경계를 확인하고, 일반 역할에서 관리자 동작을 호출해 수직 경계를 확인한다. 실패 응답뿐 아니라 응답 크기, 캐시, 부수 효과도 비교한다.

취약점보다 불변식을 찾기

BOLA는 /users/123/users/124로 바꾸는 기계적 트릭이 아니라 “현재 주체가 이 객체의 소유자 또는 허용된 관계인가”라는 불변식의 누락이다. Mass Assignment는 JSON에 필드를 더하는 것보다 서버가 허용 목록으로 쓰기 가능한 필드를 제한하는지로 판단한다. 과도한 데이터 노출은 내부 ID가 있다는 사실 자체가 아니라 클라이언트가 필요로 하지 않는 민감 정보가 권한 없이 반환되는지로 기록한다.

입력 검증은 타입·길이·인코딩·중첩 깊이·콘텐츠 타입을 경계값으로 확인하고, 주입 테스트는 격리된 fixture에서 무해한 표식으로 수행한다. 레이트 리밋은 IP 하나만 바꾸어 “우회”하려 하지 말고, 계정·토큰·작업·테넌트 기준이 일관된지와 실패 시 부수 효과가 없는지를 검증한다. GraphQL은 introspection 노출 여부만으로 취약점이라 하지 않고, 권한·쿼리 깊이·배치 비용을 함께 본다.

재현성과 보고

자동화는 동일한 요청을 반복하는 데 쓰기보다 권한 행렬과 회귀 조건을 코드로 고정하는 데 쓴다. 각 발견에는 전제 조건, 최소 재현 요청, 실제/기대 응답, 영향받는 주체, 데이터 변경 여부, 수정 후 통과 기준을 포함한다. 토큰과 개인정보는 마스킹한다. 수정은 라우트 하나의 조건문이 아니라 서비스 계층의 인가 정책과 테스트로 닫아야 한다.

좋은 API 테스트 보고서는 “공격이 가능하다”에서 멈추지 않는다. 어떤 주체가 어떤 객체에 어떤 상태에서 접근했고, 서버가 어느 판단을 생략했으며, 그 판단을 어디에 넣으면 회귀를 막는지를 보여준다.