깨고 구축하기: CTF와 버그 바운티가 시스템 설계를 재구성한다
Source: Dev.to
소프트웨어 엔지니어는 창조자가 되도록 훈련받습니다. 제품 요구사항 문서를 바라보고, 해피 패스를 설계하고, 로직을 작성하고, 단위 테스트를 통과시키고, 배포합니다. 우리의 기본적인 사고 모델은 “이 시스템을 어떻게 동작하게 할까?” 라는 건설적인 방향입니다.
하지만 크라우드소싱 현상금 플랫폼에서 버그를 사냥하거나 새벽 3시까지 CTF(캡처 더 플래그) 대회에 참여해 본 적이 있다면, 여러분의 뇌는 영구적인 구조적 변화를 겪게 됩니다. 코드를 단순히 비즈니스 요구사항을 구현한 것으로 보지 않게 됩니다. 대신 공격 표면으로 바라보게 됩니다.
보안 공격 측면에서 활동하면 코드 작성 방식과 분산 시스템 설계 방식이 완전히 바뀝니다. 새로운 기능을 구현하고 키보드를 놓는 순간, 두 번째 생각이 즉시 떠오릅니다:
“내가 이 시스템을 목표로 한다면, 방금 만든 코드를 어떻게 부수겠는가?”
아래는 공격 보안이 여러분의 엔지니어링 본능에 새겨 넣는 핵심 시스템 설계 교훈들입니다.
1. “신뢰할 수 있는 데이터베이스” 신화 제거
전통적인 소프트웨어 엔지니어링에서 흔히 발생하는 실수는 암묵적인 신뢰 경계에 의존한다는 점입니다. 개발자는 직접적인 사용자 입력(예: POST 요청 본문)에 대해서는 자연스럽게 편집증을 갖지만, 데이터가 데이터베이스에 기록되면 경계를 낮춥니다. SELECT 쿼리 결과를 본질적으로 안전하다고 여깁니다.
SSTI(서버‑사이드 템플릿 인젝션) 혹은 저장된 XSS와 같은 취약점을 이해한 공격자는 이 안일함을 정확히 이용합니다. 무해해 보이는 필드(예: 프로필 사용자명이나 주소)에 페이로드를 삽입하고, 데이터베이스에 그대로 두었다가 백엔드가 이를 나중에 가져와 고권한 처리 싱크나 HTML 렌더링 엔진에 비정제 상태로 전달하도록 기다립니다.
[Attacker Payload] ──► [Inbound Request] ──► [Database (Stored Plaintext)]
│
Backend fetches data later
│
▼
[Malicious Execution Sink] ◄── [No Validation] ◄── [App Read Layer]
CTF 경험은 제로 트러스트 입력/반사 정책을 엄격히 적용하도록 강요합니다:
- 모든 데이터 포인트는 처리 컨텍스트에 들어올 때마다—인증되지 않은 웹훅이든, 보안 API 호출이든, 혹은 자체 PostgreSQL 데이터베이스에서 반사된 것이든—방사능에 오염된, 신뢰할 수 없는 데이터로 취급합니다.
- 정제와 구조적 타입 검사는 네트워크 경계뿐 아니라 각 실행 싱크의 경계에서도 이루어져야 합니다.
2. IDOR 제거를 위한 강경 경계 설계
Insecure Direct Object References (IDOR) 은 실제 현상금 버그 보상에서 가장 많이 등장하는 이유가, 매우 쉽게 악용될 수 있지만 파괴력은 막대하기 때문입니다. IDOR은 시스템이 내부 데이터베이스 레코드에 대한 직접 참조(예: 순차 정수나 평문 UUID)를 API 엔드포인트를 통해 노출하고, 요청한 사용자가 해당 리소스의 소유자인지 검증하지 않을 때 발생합니다.
버그 바운티 마인드셋을 가진 개발자는 orgId 혹은 userId 와 같이 쿼리 파라미터 혹은 가변 헤더에 직접 노출된 값을 보자마자 레드 플래그를 띕니다: “이 숫자를 바꾸면 다른 사람의 데이터를 읽을 수 있다.”
이 취약점을 완전히 회피하려면 진실의 근원을 클라이언트가 제어할 수 없는 곳에 두어야 합니다. 요청 파라미터를 신뢰해 조직이나 사용자를 식별하지 말고, 암호학적으로 서명된 세션 컨텍스트 혹은 게이트웨이 레벨에서 검증된 불변 JWT에서만 식별자를 추출하도록 합니다.
보안 패턴
GET /api/v1/organization/myDetails
백엔드는 활성 세션 토큰에 묶인 불변, 검증된 orgId 를 추출해 데이터베이스에 질의합니다. 클라이언트가 HTTP 파라미터를 조작하더라도, 질의를 구동하는 변수를 제어하지 못하므로 범위를 벗어난 상태 전환을 강제할 수 없습니다.
3. 컴포넌트 설계 시 SSRF와 CSRF 예측
SSRF(서버‑사이드 요청 위조) 챌린지에서 방화벽을 우회하는 복잡한 페이로드를 만들며 수시간을 보낸 뒤에는 내부 네트워킹 컴포넌트를 전혀 다른 시각으로 설계하게 됩니다.
백엔드가 웹훅 알림 기능을 지원하거나 사용자 제공 URL에서 이미지를 가져와야 할 경우, 보안에 무관심한 구현은 단순히 표준 HTTP 클라이언트 라이브러리를 사용해 요청을 발송합니다. 공격적인 사고방식은 즉시 취약점을 예측합니다: 공격자는 http://127.0.0.1:8500/ 혹은 내부 AWS 메타데이터 엔드포인트(http://169.254.169.254/)를 전달해 내부 VPC를 스캔하려 할 수 있습니다.
이를 인지하고 인프라 설계에 방어성을 직접 삽입합니다:
- 사용자 제공 URL에 대한 egress 트래픽을 샌드박스된 네트워크 세그먼트에 격리합니다.
- 도메인 혹은 IP 대역을 화이트리스트로 검증한 뒤에만 외부 요청을 수행합니다.
- 시간 제한 및 크기 제한을 적용해 가져온 리소스가 DoS 벡터가 되지 않도록 합니다.
- “기본 차단(deny‑by‑default)” 규칙을 내부 서비스에 적용해 반드시 필요한 것만 노출합니다.
4. (보너스) CSRF를 설계 단계에서 다루기
인증된 요청을 위조하는 CTF 연습은 Cross‑Site Request Forgery (CSRF) 를 엔드포인트를 설계하는 순간부터 고려하게 합니다. 사후에 CSRF 토큰을 추가하기보다, 처음부터 다음 관행을 적용합니다:
- 세션 식별자에 SameSite 쿠키(
SameSite=Strict혹은Lax)를 사용합니다. - 상태를 변경하는
POST,PUT,PATCH,DELETE요청에는 명시적인 anti‑CSRF 토큰을 요구합니다. - 쿠키를 읽을 수 없는 API(SPA 등)에서는 double‑submit 쿠키 패턴을 활용합니다.
- 가능한 경우 API를 멱등(idempotent) 으로 설계해 재전송 요청의 영향을 최소화합니다.
마무리 생각
공격 보안 마인드셋을 채택한다는 것은

