최신 트렌드

OWASP 오픈소스 완벽 가이드 - Top 10·ZAP·Dependency-Check로 백엔드 보안 기본기 다지기

백엔드 개발자 김승원 2026. 4. 23. 10:41

들어가며

LLM 가드레일(#129)과 중앙 MCP 허브(#130)까지 올리고 나면 한 가지 질문이 남습니다. "AI 방어선은 올렸는데, 정작 우리 백엔드 웹 애플리케이션 자체의 보안은 어디까지 됐지?"

SQL Injection, XSS, 인증 우회, 취약한 의존성 같은 고전 취약점은 AI가 등장했다고 사라지지 않습니다. 오히려 AI가 생성한 코드에서 더 자주 등장하고, LLM 에이전트가 호출하는 내부 API가 공격 표면이 되면서 위험이 커졌습니다.

이 "고전적 웹 보안"의 사실상 표준이 OWASP(Open Worldwide Application Security Project)입니다. 오늘은 현직 백엔드 개발자가 바로 써야 할 OWASP 오픈소스 프로젝트들을 한 번에 정리합니다.

  • 1부 - OWASP 조직과 주요 프로젝트 지도
  • 2부 - OWASP Top 10 / API Top 10 / LLM Top 10 핵심 요약
  • 3부 - Dependency-Check로 취약 라이브러리 자동 탐지(Gradle/CI)
  • 4부 - ZAP으로 동적 보안 스캔 자동화
  • 5부 - ASVS·Cheat Sheets·SAMM을 실무 리뷰 체크리스트로 쓰기
  • 6부 - Spring Boot 적용 예시와 CI/CD 파이프라인 통합

1. OWASP가 뭐길래

OWASP는 2001년에 설립된 비영리 재단으로, 웹 애플리케이션 보안에 관한 문서·도구·표준을 전부 무료·오픈소스로 공개합니다. 회사 소속 보안팀이 없는 팀이라도 OWASP만 제대로 활용하면 "최소한의 합리적 보안" 수준은 맞출 수 있습니다.

수십 개 프로젝트가 있지만 현장에서 실제로 쓰이는 것은 몇 가지로 좁혀집니다.

프로젝트 유형 한 줄 용도
OWASP Top 10 문서 가장 위험한 웹 취약점 10개 리스트
API Security Top 10 문서 REST/GraphQL 등 API 전용 Top 10
LLM Top 10 문서 LLM·에이전트 애플리케이션 전용
ASVS 표준 보안 요구사항 체크리스트(Level 1~3)
Cheat Sheets 문서 주제별 실무 구현 가이드
SAMM 모델 팀/조직 보안 성숙도 평가
Dependency-Check 도구(SCA) 라이브러리 CVE 자동 탐지
ZAP 도구(DAST) 실행 중인 웹앱 동적 스캐닝
Juice Shop 실습 취약점 100여 개 심어둔 연습용 앱
CRS(ModSecurity) 룰셋 WAF용 공통 룰셋

팀에 처음 도입한다면 Top 10 → Dependency-Check → ZAP → ASVS 순으로 들어오는 것이 가장 자연스럽습니다.

2. OWASP Top 10 (2021) 요약

4년 주기로 개정되며 가장 최근 안정판은 2021년 버전입니다. 2025년 개정안도 공개 리뷰 중이지만 실무 기준은 여전히 2021입니다.

# 항목 대표 사례
A01 Broken Access Control IDOR, 권한 우회
A02 Cryptographic Failures 평문 저장, 약한 해시
A03 Injection SQLi, XSS, 명령어 주입
A04 Insecure Design 비율 제한 부재, 위협 모델 부재
A05 Security Misconfiguration 디폴트 비번, 노출된 actuator
A06 Vulnerable & Outdated Components log4shell, 오래된 라이브러리
A07 Identification & Auth Failures 크리덴셜 스터핑, 세션 탈취
A08 Software & Data Integrity Failures 공급망 공격, 서명 없는 업데이트
A09 Security Logging & Monitoring Failures 감사 로그 부재
A10 SSRF 내부 메타데이터 서버 접근

백엔드 개발자 관점에서 가장 자주 부딪히는 상위 3개는 A01·A03·A05입니다. 이 셋은 코드 리뷰 단계에서 잡아야 후행 비용이 없습니다.

API Security Top 10 (2023)

REST API를 쓰는 현대 백엔드라면 Top 10보다 API Top 10이 더 가까운 체크리스트입니다. OAuth 2.0/OIDC와 같이 봐야 이해가 빠릅니다.

  • API1 BOLA - 객체 수준 인가 실패(GET /users/123에 남의 id를 넣어도 됨)
  • API2 Broken Authentication - JWT 시크릿 노출, 리프레시 토큰 미관리
  • API3 BOPLA - 속성 수준 인가 실패(role="admin" 바디 주입으로 권한 상승)
  • API4 Unrestricted Resource Consumption - 비율 제한·페이지네이션 부재
  • API5 Broken Function Level Authorization - /admin/*에 일반 사용자 접근 가능
  • API6 Unrestricted Access to Sensitive Business Flows - 자동화된 구매·적립 악용
  • API7 SSRF
  • API8 Security Misconfiguration
  • API9 Improper Inventory Management - v1·v2·v3 섞여 있고 v1이 인증 없음
  • API10 Unsafe Consumption of APIs - 외부 API 응답을 검증 없이 신뢰

LLM Top 10 (2025)

LLM·에이전트 전용 Top 10도 정식 프로젝트로 올라왔습니다. 프롬프트 인젝션부터 민감 정보 유출까지 10개 항목으로 정리돼 있는데, 자세한 대응 코드는 이미 #129 LLM 보안 가드레일#130 MCP 가드레일 허브에서 다뤘습니다. 여기서는 "OWASP 문서 한 장으로 요약돼 있다" 정도만 기억해 두세요.

3. Dependency-Check - 취약 라이브러리 자동 탐지

Top 10 중 A06(취약한 컴포넌트)은 가장 자동화하기 쉬운 항목입니다. Dependency-Check가 NVD의 CVE 데이터베이스를 긁어와 프로젝트 의존성과 매칭합니다.

3-1. Gradle 플러그인 설정

// build.gradle.kts
plugins {
    id("org.owasp.dependencycheck") version "10.0.4"
}

dependencyCheck {
    failBuildOnCVSS = 7.0f           // High 이상이면 빌드 실패
    formats = listOf("HTML", "JSON")
    suppressionFile = "config/owasp-suppressions.xml"
    nvd {
        apiKey = System.getenv("NVD_API_KEY")  // 필수(2023년부터)
    }
    analyzers {
        assemblyEnabled = false      // .NET 분석 비활성
        nodeAuditEnabled = true
    }
}

3-2. 실행과 리포트

$ ./gradlew dependencyCheckAnalyze
$ open build/reports/dependency-check-report.html

리포트에는 CVE 번호, CVSS 점수, 영향받는 JAR, 수정 버전 정보가 나옵니다. log4shell이 터졌을 때 이 도구 하나로 수천 개 레포의 영향 범위를 30분 안에 파악한 팀이 많았습니다.

3-3. 오탐 억제 파일

CVE가 사실은 우리 코드 경로에 해당되지 않는 경우가 있습니다. 무조건 업그레이드 대신 suppress를 쓰되 반드시 notes에 이유와 재확인 일자를 남깁니다.

<!-- config/owasp-suppressions.xml -->
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
  <suppress>
    <notes>CVE-2024-XXXX: 서버사이드에서만 사용하며 해당 취약 코드 경로는 미사용. 2026-07 재확인 필요.</notes>
    <gav regex="true">^com\.example:safe-lib:.*$</gav>
    <cve>CVE-2024-XXXX</cve>
  </suppress>
</suppressions>

3-4. GitHub Actions 통합

# .github/workflows/security.yml
name: security
on:
  push: {branches: [main]}
  schedule: [{cron: "0 5 * * *"}]  # 매일 새벽 5시
jobs:
  depcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: {distribution: temurin, java-version: 21}
      - name: Run Dependency-Check
        env:
          NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
        run: ./gradlew dependencyCheckAnalyze
      - uses: actions/upload-artifact@v4
        with:
          name: depcheck-report
          path: build/reports/dependency-check-report.*

일일 스케줄 실행이 핵심입니다. 새 CVE는 매일 공개되므로 어제 안전했던 라이브러리가 오늘 아침에 취약해질 수 있습니다.

4. OWASP ZAP - 동적 보안 스캐너

Dependency-Check가 "소스코드·의존성"을 본다면, ZAP(Zed Attack Proxy)은 실행 중인 웹 애플리케이션을 바깥에서 공격해 보는 DAST 도구입니다. Burp Suite의 오픈소스 대안이라고 보면 됩니다.

4-1. 베이스라인 스캔 (가장 빠른 도입)

$ docker run --rm -v $(pwd):/zap/wrk/:rw \
    -t zaproxy/zap-stable zap-baseline.py \
    -t https://staging.myapp.internal \
    -r baseline-report.html \
    -J baseline-report.json

약 2~5분 안에 기본적인 잘못된 헤더, 디렉토리 노출, 쿠키 속성 누락 등을 체크해 줍니다. CI에서 스테이징 서버를 대상으로 돌리기에 적당합니다.

4-2. API 스캔 (OpenAPI 기반)

현대 백엔드 대부분은 Swagger/OpenAPI 스펙을 노출합니다. ZAP은 이 스펙을 먹여주면 전체 엔드포인트를 자동 크롤링·공격합니다.

$ docker run --rm -v $(pwd):/zap/wrk/:rw \
    -t zaproxy/zap-stable zap-api-scan.py \
    -t https://staging.myapp/api/v3/api-docs \
    -f openapi \
    -r api-report.html

4-3. 인증이 필요한 스캔

로그인 뒤 페이지까지 보려면 컨텍스트 파일에 스크립트 인증을 정의해야 합니다.

# auth-context.yaml (자체 간략 포맷)
env:
  contexts:
    - name: myapp
      urls: ["https://staging.myapp"]
      authentication:
        method: script
        parameters:
          scriptName: login.js
      users:
        - name: qa-bot
          credentials:
            username: qa-bot@example.com
            password: ${QA_BOT_PASSWORD}
$ docker run --rm -v $(pwd):/zap/wrk/:rw \
    -e QA_BOT_PASSWORD \
    -t zaproxy/zap-stable zap.sh -cmd \
    -autorun /zap/wrk/auth-context.yaml

4-4. GitHub Actions에 붙이기

  zap:
    needs: deploy-staging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: ZAP Baseline Scan
        uses: zaproxy/action-baseline@v0.12.0
        with:
          target: "https://staging.myapp.internal"
          fail_action: true
          cmd_options: "-a -j -m 5 -T 10"

주의할 점은 반드시 스테이징을 겨냥해야 한다는 것입니다. 프로덕션에 직접 돌리면 속도 저하·DB 쓰레기 데이터·알림 폭주가 한꺼번에 옵니다.

5. ASVS·Cheat Sheets·SAMM

5-1. ASVS를 PR 체크리스트로

ASVS(Application Security Verification Standard)는 수백 항목의 보안 요구사항을 Level 1~3로 나눠 둔 문서입니다. 팀이 "모두 지키자"고 하면 지치지만, 항목 번호를 PR 템플릿에 박아두면 강제력이 생깁니다.

<!-- .github/pull_request_template.md -->
## Security checklist (ASVS Level 1 부분 적용)
- [ ] V2.1 비밀번호는 최소 12자 이상, 공통 사전 단어 거부
- [ ] V3.3 세션 토큰은 로그아웃/비번 변경 시 무효화
- [ ] V4.1 수평/수직 권한 체크(BOLA/BFLA)를 단위 테스트로 검증
- [ ] V5.1 모든 입력 검증은 서버 측에서
- [ ] V8.3 민감정보는 URL/로그에 남기지 않음
- [ ] V12.1 업로드 파일은 MIME + 확장자 + 바이너리 시그니처 3중 검증

Level 1(필수), Level 2(민감 서비스), Level 3(고보안)로 단계적 확장이 가능합니다.

5-2. Cheat Sheets - 구현 시 바로 열어보는 참고서

Cheat Sheet Series는 주제별로 "이렇게 구현하라"를 한 페이지로 정리한 레퍼런스 모음입니다. 특히 많이 참고되는 것은 다음과 같습니다.

  • Authentication Cheat Sheet
  • Password Storage Cheat Sheet (bcrypt/argon2 파라미터 권고)
  • JWT Cheat Sheet (알고리즘 고정, none 차단 등)
  • SQL Injection Prevention
  • XSS Prevention
  • CSRF Prevention
  • REST Security
  • File Upload

구현 중 막히면 "OWASP [주제] cheat sheet"로 검색하는 습관만 들여도 엉뚱한 블로그 복붙을 피할 수 있습니다.

5-3. SAMM - 조직 성숙도 평가

SAMM(Software Assurance Maturity Model)은 팀의 보안 활동을 4개 비즈니스 기능(Governance·Design·Implementation·Verification·Operations)으로 나눠 0~3 레벨로 평가합니다. 연 1회 자체 평가해서 어느 영역이 뒤처졌는지를 보는 데 유용합니다.

레벨 의미
0 활동 없음
1 초기/비공식
2 체계적 적용
3 조직 전반 지속 개선

현실적으로 스타트업은 전 영역 Level 1, 중견 조직은 Level 2를 목표로 잡는 경우가 많습니다.

6. Spring Boot 실전 적용

OWASP Top 10 주요 항목을 Spring Boot에서 어떻게 막는지 Spring Security 6 가이드와 연결해 정리합니다.

6-1. A01 Broken Access Control

// IDOR 방지: 항상 "본인 것"인지 확인
@GetMapping("/orders/{id}")
@PreAuthorize("isAuthenticated()")
public OrderResponse get(@PathVariable Long id,
                        @AuthenticationPrincipal UserDetails me) {
    Order o = orderRepository.findById(id)
        .orElseThrow(NotFoundException::new);
    if (!o.getOwnerEmail().equals(me.getUsername())) {
        throw new AccessDeniedException("not your order");
    }
    return OrderResponse.from(o);
}

URL 파라미터만으로 접근을 허용하는 API는 전수 감사를 돌려야 합니다. BOLA 한 건이 SNS에 올라가면 사고 등급이 바로 올라갑니다.

6-2. A03 Injection

// JPA: 파라미터 바인딩 항상 사용
@Query("select u from User u where u.email = :email")
Optional<User> findByEmail(@Param("email") String email);

// 절대 금지: 문자열 합치기
// "select * from users where email = '" + email + "'"

Thymeleaf 같은 템플릿 엔진은 기본 이스케이프가 켜져 있지만, th:utext는 명시적으로 원문 출력이라 입력을 그대로 넣는 순간 저장형 XSS가 됩니다.

6-3. A05 Security Misconfiguration - Actuator

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info     # 최소 노출
  endpoint:
    health:
      show-details: when_authorized
  server:
    port: 9090                    # 관리 포트 분리

디폴트로 /actuator/env, /actuator/heapdump가 열린 채로 프로덕션에 올라가면 비밀번호·JDBC URL이 그대로 노출됩니다. 관리 포트 분리 + 내부망만 허용 + 인증 필수가 3종 세트입니다.

6-4. A07 Auth Failures - 비율 제한

// 로그인 엔드포인트에만 Bucket4j 적용
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
    private final Bucket bucket = Bucket.builder()
        .addLimit(Bandwidth.simple(10, Duration.ofMinutes(1)))
        .build();

    @PostMapping("/login")
    public TokenResponse login(@RequestBody LoginRequest req) {
        if (!bucket.tryConsume(1)) {
            throw new TooManyRequestsException("rate limit");
        }
        return authService.login(req);
    }
}

실제로는 IP/계정 두 축으로 각각 버킷을 둬야 크리덴셜 스터핑을 막을 수 있습니다.

6-5. 공통 응답 헤더

// SecurityConfig
http.headers(h -> h
    .contentSecurityPolicy(csp -> csp.policyDirectives(
        "default-src 'self'; object-src 'none'; frame-ancestors 'none'"))
    .httpStrictTransportSecurity(hsts -> hsts
        .includeSubDomains(true).maxAgeInSeconds(31536000))
    .xssProtection(xss -> xss.headerValue(
        XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))
    .frameOptions(f -> f.deny())
    .referrerPolicy(r -> r.policy(
        ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN))
);

7. CI/CD 보안 게이트 통합

도구가 아무리 좋아도 PR을 블록하지 않으면 아무도 안 본다는 게 현장 진리입니다. 단계별 게이트를 정합니다.

단계 도구 차단 기준
코드 커밋 pre-commit(secrets scan) 키/토큰 패턴 발견 시
PR 빌드 Dependency-Check CVSS 7.0 이상
PR 빌드 SpotBugs + Find Sec Bugs High 이상
스테이징 배포 후 ZAP Baseline High 경고 1건 이상
스테이징 정기 ZAP API Scan 리포트 Slack 전송
프로덕션 배포 Cosign 서명 검증 서명 없음 시 차단
운영 SIEM 알림 비정상 인증 패턴

7-1. pre-commit 예시(시크릿 유출 방지)

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.0
    hooks:
      - id: gitleaks

7-2. 종합 GitHub Actions 샘플

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: {distribution: temurin, java-version: 21}
      - run: ./gradlew check spotbugsMain
      - run: ./gradlew dependencyCheckAnalyze
        env: {NVD_API_KEY: ${{ secrets.NVD_API_KEY }}}
      - uses: actions/upload-artifact@v4
        with: {name: sast, path: build/reports/}

  dast:
    needs: [sast, deploy-staging]
    runs-on: ubuntu-latest
    steps:
      - uses: zaproxy/action-api-scan@v0.7.0
        with:
          target: https://staging.myapp/api/v3/api-docs
          format: openapi
          fail_action: true

8. Juice Shop으로 팀 훈련

OWASP Juice Shop은 "일부러 취약하게 만든 Node.js 쇼핑몰"입니다. 신규 입사자 온보딩 주에 2시간만 투자해 몇 가지 챌린지를 풀게 해도 보안 감수성이 완전히 달라집니다.

$ docker run --rm -p 3000:3000 bkimminich/juice-shop
# http://localhost:3000
  • 쉬움: 관리자 이메일 찾기, 포럼에 스크립트 실행시키기(XSS)
  • 중간: 남의 장바구니 조작(BOLA), JWT 알고리즘 교체
  • 어려움: 서버 측 템플릿 인젝션, Blind SQLi

진도 체크는 내장 /#/score-board에서 자동으로 이뤄지므로 사내 교육 KPI로 잡기도 좋습니다.

9. OWASP를 쓸 때 흔히 하는 실수

  • Top 10만 보고 끝내기 - Top 10은 입문용 리스트입니다. 실제 요구사항은 ASVS, 구현은 Cheat Sheet로 이어가야 완결됩니다.
  • ZAP을 프로덕션에 돌리기 - DB에 쓰레기 데이터와 사용자 알림 폭주를 부릅니다. 반드시 스테이징 전용.
  • Dependency-Check를 주간으로만 돌리기 - 새 CVE는 매일 뜹니다. 일일 스케줄 + PR 블로킹이 기본.
  • suppressions 남발 - 사유 없이 억제한 CVE는 6개월 뒤 사고의 원인이 됩니다. 반드시 notes + 재확인 일자.
  • SAMM을 한 번 평가하고 끝 - 최소 반기·연 1회 재평가하지 않으면 의미 없음.
  • 보안팀에만 맡기기 - OWASP의 핵심 철학은 "개발자 중심"입니다. 개발자가 읽고 PR 단계에서 적용해야 가치가 나옵니다.

10. 30일 도입 로드맵

기간 목표 산출물
1주차 Top 10 스터디, 자체 레포 감사 위험도 매트릭스
2주차 Dependency-Check 도입, CI 연동 일일 리포트 Slack 전송
3주차 ZAP Baseline 자동 스캔 스테이징 주간 리포트
4주차 ASVS Level 1 체크리스트를 PR 템플릿에 내장 PR 체크리스트
2~3개월 SAMM 자체 평가, 보안 챔피언 제도 조직 성숙도 리포트

팀 규모에 따라 늘이고 줄일 수 있지만, 순서를 뒤집으면 피로도가 크게 올라갑니다. "눈에 보이는 효과"가 빠른 Dependency-Check부터 시작하는 것이 도입 성공률이 가장 높습니다.

마치며

OWASP 오픈소스 생태계 도입의 핵심 포인트를 정리합니다.

  • OWASP는 문서·표준·도구가 한 세트로 연결된 프로젝트 집합입니다. Top 10으로 감을 잡고, Dependency-Check·ZAP으로 자동화하고, ASVS·Cheat Sheet로 코드 리뷰 기준을 세우는 흐름이 가장 자연스럽습니다. 따로 놓고 쓰지 말고 서로 연결해서 운영해야 효과가 납니다.
  • Top 10만으론 부족합니다. 백엔드 API 개발자는 API Top 10을, LLM 에이전트를 붙인 서비스라면 LLM Top 10까지 함께 봐야 현재 위협 지형이 맞게 잡힙니다. #129·#130과 같이 보면 "고전+AI" 축이 한 번에 덮입니다.
  • Dependency-Check는 오늘 당장 붙일 수 있는 가장 ROI 높은 도구입니다. 30분이면 Gradle 플러그인과 CI 연동이 끝나고, 다음 날 새벽 리포트부터 실제 CVE가 보입니다. 일일 스케줄 + CVSS 7.0 이상 PR 블로킹을 권장합니다.
  • ZAP은 Baseline → API Scan → 인증 스캔 순으로 단계적으로 올리세요. 스테이징 전용으로 제한하고, 인증이 필요한 플로우까지 커버되면 외부 펜테스트 비용의 상당 부분을 내재화할 수 있습니다.
  • ASVS와 Cheat Sheet는 "읽는 문서"가 아니라 "PR 템플릿과 리뷰 체크리스트에 박는 문서"입니다. 프로젝트 위키 구석에 링크만 두면 아무도 안 봅니다. Level 1 필수 항목부터 .github/pull_request_template.md에 넣으세요.
  • Juice Shop은 온보딩 주 2시간짜리 보안 감수성 훈련으로 최적입니다. 신규 입사자가 직접 BOLA와 XSS를 성공시켜 보면, 이후 코드 리뷰 품질이 눈에 띄게 올라갑니다. 보안 교육 예산이 0원인 팀에도 가능한 옵션입니다.

AI 시대에도 웹 보안의 상당 부분은 여전히 "지루하지만 알려진 문제"입니다. 새 CVE를 매일 따라잡고, 자동화로 피로도를 낮추는 인프라만 깔아두면 조직 전체의 보안 바닥이 한 계단 올라갑니다. 다음 글에서는 이 OWASP 기반 파이프라인 위에 SBOM(소프트웨어 자재명세서)과 공급망 서명(Sigstore/cosign)을 얹어 A08(Software & Data Integrity Failures)까지 닫는 방법을 다뤄볼 예정입니다.