← all posts
DEV 2026.05.02 · 14 min read Intermediate

보안은 도구가 아니라 파이프라인이다

SAST, DAST, 침투 테스트, 보안 로깅, 인시던트 대응까지 — 코드가 배포되기 전부터 사고가 난 뒤까지, 보안 엔지니어링의 전체 흐름을 추적한다.


보안 도구를 도입하는 것과 보안 파이프라인을 설계하는 것은 다르다. 도구는 특정 지점의 취약점을 잡지만, 파이프라인은 코드 작성 순간부터 사고 대응까지 전 구간에 검증을 심는다. 그렇다면 Spring Boot 애플리케이션을 중심으로 이 파이프라인을 처음부터 끝까지 구성하면 어떤 결정이 필요한가?

코드 작성 단계: SAST가 첫 번째 문이다

정적 분석(SAST)은 코드가 실행되기 전에 작동한다. SQL 문자열 연결, 스택 트레이스를 응답에 담는 패턴, 하드코딩된 자격증명 — 이 모든 것은 런타임 없이도 탐지할 수 있다.

SpotBugs와 FindSecBugs 플러그인은 버그 패턴을 탐지하고, SonarQube는 보안 규칙을 종합 검사한다. 두 도구를 병렬로 사용하는 이유는 역할이 다르기 때문이다. SpotBugs는 패턴 매칭에 강하고, SonarQube는 데이터 흐름 분석으로 컨텍스트를 본다.

plugins {
    id 'com.github.spotbugs' version '6.0.0'
}

spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0'

spotbugs {
    effort = com.github.spotbugs.snom.Effort.MAX
    reportLevel = com.github.spotbugs.snom.Confidence.LOW
}

Gitleaks는 커밋 이력을 스캔한다. AWS 키, Slack 토큰, 비밀번호 패턴이 커밋에 들어가는 순간을 포착한다. pre-commit 훅이나 CI 초기 단계에 배치해야 한다 — 커밋 이후에 발견하면 이미 git 이력에 남는다.

SAST의 한계

SAST는 정적 분석이므로 런타임에서 결정되는 취약점은 잡을 수 없다. 타이밍 공격, 경쟁 조건, 설정 파일 기반 취약점은 DAST와 침투 테스트의 영역이다.

배포 단계: DAST가 실행 중인 앱을 실제로 공격한다

DAST(동적 분석)는 SAST가 보지 못하는 것을 본다. OWASP ZAP은 실행 중인 애플리케이션에 실제 공격 페이로드를 전송한다.

Passive 스캔은 트래픽을 분석하고, Active 스캔은 직접 공격한다. CI/CD에서는 두 단계를 순서대로 배치한다 — Passive는 모든 PR에, Active는 스테이징 배포 후에.

- name: ZAP Passive Scan
  uses: zaproxy/action-full-scan@v0.7.0
  with:
    target: 'http://localhost:8080'

- name: Check ZAP Results
  run: |
    CRITICAL=$(jq '.alerts[] | select(.riskcode=="3") | length' report.json)
    if [ "$CRITICAL" -gt 0 ]; then
      echo "Security threshold exceeded"
      exit 1
    fi

임계값 설정이 핵심이다. Critical 취약점은 0개, High는 3개 이하처럼 명시적 기준을 코드에 박아야 한다. “나중에 처리”는 영원히 처리되지 않는다.

릴리스 전: 침투 테스트는 공격자 관점으로 검증한다

자동화 도구는 알려진 패턴을 찾는다. 침투 테스트는 알려지지 않은 설계 결함을 찾는다. IDOR(Insecure Direct Object Reference)가 대표적이다.

// 권한 확인 없이 userId를 URL에서 그대로 받는 패턴
@GetMapping("/api/users/{userId}/profile")
public ResponseEntity<?> getProfile(@PathVariable Long userId) {
    return ResponseEntity.ok(userRepository.findById(userId).orElseThrow());
}
// GET /api/users/2/profile → 다른 사용자의 데이터가 반환된다

Burp Suite의 Intruder로 userId를 1부터 10,000까지 순회하면, 응답 길이가 달라지는 패턴으로 접근 가능한 계정을 자동으로 식별한다. 방어는 단순하다 — 요청한 사용자가 대상 리소스의 소유자인지, 또는 충분한 권한이 있는지를 매 요청마다 확인해야 한다.

침투 테스트 체크리스트는 인증, 세션, 권한, 입력 검증, 비즈니스 로직, API 보안, 인프라 총 7개 영역을 포함한다. 자동화 도구가 커버하지 못하는 비즈니스 로직 영역 — 가격 조작, 결제 단계 우회, 레이스 컨디션 — 은 수동 테스트로만 발견된다.

운영 단계: 로깅이 없으면 사고는 미스터리로 끝난다

Equifax 사건(2017)에서 공격자는 3개월간 데이터를 탈취했다. 로깅이 없어 언제 어디서 침입이 시작됐는지 끝내 추적하지 못했다. 7억 달러 합의금보다 추적 불가능이라는 결과가 더 치명적이었다.

Spring AOP로 보안 이벤트를 선언적으로 기록한다.

@SecurityEvent(action = "LOGIN", resourceType = "USER_ACCOUNT")
public ResponseEntity<?> login(String username, String password) { ... }

@SecurityEvent(action = "DATA_ACCESS", resourceType = "PII")
public List<UserDetailDto> exportAllUserDetails() { ... }

어노테이션 하나로 누가, 언제, 어디서, 무엇을 했는지가 자동으로 기록된다. 비정상 패턴 감지는 그 위에 쌓인다 — 1분에 5회 이상 로그인 실패는 계정 잠금, 5분에 10회 이상 접근 거부는 IDOR 시도 경보.

로그는 중앙에서 수집해야 한다. ELK Stack이나 CloudWatch Logs로 Elasticsearch에 모으면 1시간 내 로그인 실패 5회 이상을 쿼리 한 줄로 추적할 수 있다.

트레이드오프

모든 메서드를 로깅하면 성능 영향이 걱정된다. AOP 기반 비동기 로깅은 메인 스레드를 블로킹하지 않으므로 오버헤드는 작다. 더 현실적인 비용은 저장소 비용이다 — S3 Glacier 계층이나 ELK의 30일 자동 삭제 정책으로 관리한다. 과도한 로깅보다 과소한 로깅이 훨씬 더 위험하다.

사고 발생 후: 대응 계획 없으면 패닉이 프로세스가 된다

Uber(2022)는 침해를 발견하고 5시간 동안 아무것도 하지 않았다. 그 사이 공격자는 계속 접근했다. 문제는 기술이 아니라 프로세스의 부재였다.

인시던트 대응은 네 단계다: Containment(격리) → Investigation(조사) → Recovery(복구) → Post-Mortem(사후 분석). 각 단계에 담당자, 시간 기준, 행동 지침이 사전에 정의되어 있어야 한다.

포렌식 증거는 수집 시점부터 체인 오브 커스터디(Chain of Custody)를 기록해야 한다 — SHA-256 해시로 무결성을 검증하고, RSA 서명으로 조작 여부를 추적하는 방식으로. 증거 체인이 없으면 법적 절차에서 증거로 인정받지 못한다.

한국 개인정보보호법(PIPA)과 GDPR은 침해 발견 후 72시간 내 사용자 통지를 요구한다. 공지 내용, 연락 채널, 콜센터 운영까지 사전에 준비된 템플릿이 있어야 72시간 안에 실행할 수 있다.

정리

  • SAST(SpotBugs, SonarQube, Gitleaks)는 코드 작성 단계에서 알려진 패턴을 자동으로 차단한다.
  • DAST(OWASP ZAP)는 실행 중인 앱을 실제 공격으로 검증하고, 임계값을 초과하면 빌드를 멈춘다.
  • 침투 테스트는 자동화가 보지 못하는 설계 결함 — IDOR, 비즈니스 로직 우회 — 을 공격자 관점으로 드러낸다.
  • 보안 로깅은 Spring AOP로 선언적으로 자동화하고, 비정상 패턴 감지까지 연결해야 운영 단계에서 침해를 추적할 수 있다.
  • 인시던트 대응 계획은 사고 전에 작성해야 한다. 사고 중에 작성하면 패닉이 프로세스가 된다.

보안은 도구가 아니라 파이프라인이다. 각 도구가 커버하지 못하는 구간을 다음 도구가 메우도록 설계하는 것이 보안 엔지니어링의 핵심이다.