콘텐츠로 이동

애플리케이션

각 애플리케이션은 VM의 nginx 리버스 프록시를 통해 접근 가능한 nginx 업스트림 풀 뒤에서 4개의 로드 밸런싱된 Docker 컨테이너로 실행됩니다. 스티키 세션은 상태 저장 애플리케이션(Juice Shop, DVWA, VAmPI, CSD Demo)이 일관되게 라우팅되도록 보장합니다. 모든 애플리케이션은 의도적으로 취약하게 설계되어 보안 테스트용으로 만들어졌습니다.

아래 모든 예제에서 <ORIGIN>http://<PUBLIC_IP>로 교체하십시오. Terraform을 통해 배포한 후 terraform output -raw public_ip로 IP를 확인하십시오.

경로애플리케이션HTTP 메서드예상 응답
/랜딩 페이지GET모든 앱 링크가 포함된 200 HTML
/health헬스 체크GET200 JSON {"status":"healthy","component":"origin-server",...}
/juice-shop/Juice ShopGET200 HTML (Angular SPA, ~75 KB)
/juice-shop/rest/products/search?q=Juice Shop APIGET200 JSON {"status":"success","data":[...]} (36개 상품)
/dvwa/DVWAGET/dvwa/login.php로 302 리다이렉트
/dvwa/login.phpDVWA 로그인GET200 HTML 로그인 폼
/dvwa/setup.phpDVWA 설정GET200 HTML (최초 실행 데이터베이스 초기화)
/vampi/VAmPIGET200 HTML (API 문서)
/vampi/users/v1VAmPI APIGET200 JSON {"users":[...]}
/vampi/users/v1/registerVAmPI APIPOST200 JSON {"status":"success",...}
/vampi/users/v1/loginVAmPI APIPOST200 JSON {"auth_token":"...","status":"success"}
/httpbin/gethttpbinGET요청 세부 정보가 포함된 200 JSON
/httpbin/posthttpbinPOST게시된 데이터가 포함된 200 JSON
/httpbin/headershttpbinGET200 JSON {"headers":{...}}
/httpbin/status/:codehttpbinGET지정된 HTTP 상태 코드 반환
/whoami/whoamiGET호스트명, IP, 모든 헤더가 포함된 200 일반 텍스트
/csd-demo/CSD DemoGET공격 패널이 있는 200 HTML 체크아웃 폼
/csd-demo/dashboardCSD 공격자 뷰GET유출된 데이터를 보여주는 200 HTML
/csd-demo/healthCSD 헬스GET200 JSON {"status":"healthy","component":"csd-demo",...}
/csd-demo/exfil/logCSD 유출 로그GET캡처된 데이터의 200 JSON 배열
/dvga/DVGA GraphiQLGET200 HTML (GraphiQL IDE)
/dvga/graphqlDVGA GraphQL APIPOST200 JSON GraphQL 응답
/restaurant/RESTaurantGET200 (문서로 리다이렉트)
/restaurant/docsRESTaurant SwaggerGET200 HTML (FastAPI Swagger UI)
/restaurant/openapi.jsonRESTaurant OpenAPIGET200 JSON OpenAPI 사양
http://<PUBLIC_IP>:8888crAPIGET200 HTML (SPA)
http://<PUBLIC_IP>:8888/identity/api/auth/signupcrAPI 회원가입POST200 JSON
http://<PUBLIC_IP>:8888/identity/api/auth/logincrAPI 로그인POST200 JSON {"token":"..."}
경로/juice-shop/
이미지bkimminich/juice-shop:latest
인스턴스4개 (포트 3001-3004), hash $cookie_token을 통한 스티키, 프록시 캐시 (60초 TTL)
리소스인스턴스당 CPU 2개 / RAM 1 GiB
프레임워크Node.js / Angular
프로젝트owasp.org/www-project-juice-shop

OWASP Juice Shop은 가장 현대적이고 활발히 유지 관리되는 취약한 웹 애플리케이션입니다. 실제 전자상거래 애플리케이션에서 100개 이상의 챌린지로 OWASP Top 10 전체를 다룹니다.

시나리오카테고리공격 벡터
SQL 인젝션 로그인 우회웹 앱 방화벽 (WAF)로그인 이메일 필드에 ' OR 1=1-- 입력
반사형 XSS웹 앱 방화벽 (WAF), 클라이언트 측 방어검색 파라미터를 통한 스크립트 인젝션
DOM 기반 XSS클라이언트 측 방어URL 프래그먼트의 페이로드
취약한 인증웹 앱 방화벽 (WAF)브루트 포스 로그인, JWT 조작
API 남용API 보안/api/ 엔드포인트에 대한 무단 접근
민감한 데이터 노출API 보안인증 없이 사용자 데이터 접근
CSRF웹 앱 방화벽 (WAF)프로필 변경에 대한 사이트 간 요청 위조
Terminal window
curl -s "http://<PUBLIC_IP>/juice-shop/" -o /dev/null -w "%{http_code}"
경로/dvwa/
이미지커스텀 dvwa-fpm:latest (php-fpm + nginx, ghcr.io/digininja/dvwa:latest에서 빌드)
인스턴스4개 (포트 8101-8104), hash $cookie_PHPSESSID를 통한 스티키
리소스인스턴스당 CPU 0.5개 / RAM 256 MiB
데이터베이스공유 MariaDB 10.11 (dvwa-db 컨테이너, CPU 1개 / 768 MiB)
프레임워크PHP 8 / php-fpm / MariaDB
자격 증명admin / password

DVWA는 웹 앱 방화벽 (WAF) 테스트의 업계 표준입니다. 점진적으로 입력 유효성 검사와 출력 인코딩을 추가하는 조정 가능한 보안 수준(낮음, 보통, 높음, 불가능)을 제공합니다.

시나리오카테고리보안 수준
SQL 인젝션웹 앱 방화벽 (WAF)낮음: 단순한 ' OR 1=1#, 높음: 블라인드 SQLi
커맨드 인젝션웹 앱 방화벽 (WAF)낮음: ; ls, 높음: 필터링된 문자
파일 인클루전웹 앱 방화벽 (WAF)낮음: 직접 경로 탐색, 높음: 정제됨
XSS (반사형)웹 앱 방화벽 (WAF), 클라이언트 측 방어낮음: 기본 <script>, 높음: 인코딩 우회
XSS (저장형)웹 앱 방화벽 (WAF), 클라이언트 측 방어낮음: 방명록에 영속적 스크립트
파일 업로드웹 앱 방화벽 (WAF)낮음: PHP 쉘 업로드, 높음: 확장자 필터링
브루트 포스Bot 표준 방어자동화된 로그인 시도

로그인 후 /dvwa/security.php에서 보안 수준을 설정하십시오:

  • 낮음 — 입력 유효성 검사 없음. 모든 공격이 작동합니다. 웹 앱 방화벽 (WAF) 시그니처 시연에 적합합니다.
  • 보통 — 기본 필터링. 일부 공격은 인코딩 또는 우회 기법이 필요합니다.
  • 높음 — 강력한 필터링. 고급 기법만 성공합니다. 웹 앱 방화벽 (WAF) 한계를 보여주기에 적합합니다.
  • 불가능 — 완전히 안전한 구현. 적절한 방어적 코딩을 시연합니다.

DVWA는 첫 번째 배포 후 일회성 데이터베이스 설정이 필요합니다:

  1. http://<PUBLIC_IP>/dvwa/setup.php로 이동합니다
  2. Create / Reset Database를 클릭합니다
  3. admin / password로 로그인합니다
경로/vampi/
이미지gunicorn 엔트리포인트(4 워커)를 사용하는 erev0s/vampi:latest
인스턴스4개 (포트 5101-5104), ip_hash를 통한 스티키 (인스턴스별 SQLite)
리소스인스턴스당 CPU 0.5개 / RAM 512 MiB
프레임워크Python / Flask / gunicorn
프로젝트github.com/erev0s/VAmPI

VAmPI는 OWASP API Security Top 10 테스트를 위해 특별히 제작되었습니다. 의도적인 취약점이 있는 현실적인 REST API를 제공합니다. 각 인스턴스는 4개의 워커와 자체 SQLite 데이터베이스로 gunicorn을 실행합니다. ip_hash 스티키 세션은 동일한 클라이언트 IP에서의 등록 및 로그인이 항상 동일한 인스턴스에 연결되도록 보장합니다.

시나리오OWASP API Top 10방법
객체 수준 인증 취약점 (BOLA)API1ID 조작으로 다른 사용자의 데이터 접근
취약한 인증API2약한 토큰 처리, 속도 제한 없음
과도한 데이터 노출API3API가 클라이언트에 필요한 것 이상의 데이터 반환
대량 할당API6예상치 못한 파라미터를 통한 관리자 필드 수정
SQL 인젝션API8API 파라미터를 통한 인젝션
부적절한 자산 관리API9문서화되지 않은 API 엔드포인트
Terminal window
# 새 사용자 등록
curl -X POST "http://<PUBLIC_IP>/vampi/users/v1/register" \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"test123","email":"test@test.com"}'
# 로그인
curl -X POST "http://<PUBLIC_IP>/vampi/users/v1/login" \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"test123"}'
# 사용자 목록 조회 (과도한 데이터 노출)
curl "http://<PUBLIC_IP>/vampi/users/v1"
경로/httpbin/
이미지gunicorn CMD 오버라이드(-w 4 -k gevent --timeout 30)를 사용하는 kennethreitz/httpbin:latest
인스턴스4개 (포트 8201-8204), 라운드 로빈 (무상태)
리소스인스턴스당 CPU 0.5개 / RAM 256 MiB
프레임워크Python / Flask / gunicorn + gevent
프로젝트httpbin.org

httpbin은 기본 API 데모, 요청 헤더 테스트 및 프록시 동작 확인에 유용한 간단한 HTTP 요청/응답 서비스입니다.

엔드포인트목적
/httpbin/getGET 요청 데이터 반환 (헤더, 인자, 출처)
/httpbin/postPOST 요청 데이터 반환 (본문, 폼, JSON)
/httpbin/headers요청 헤더 반환
/httpbin/ip출처 IP 반환
/httpbin/user-agentUser-Agent 헤더 반환
/httpbin/status/:code지정된 HTTP 상태 코드 반환
/httpbin/delay/:secondsN초 동안 응답 지연
/httpbin/anything요청에서 전달된 모든 것 반환
Terminal window
# 오리진 서버가 어떤 헤더를 받는지 확인 (F5 XC 헤더 인젝션 확인에 유용)
curl -s "http://<PUBLIC_IP>/httpbin/headers" | jq .
# 특정 HTTP 상태 코드 테스트
curl -s -o /dev/null -w "%{http_code}" "http://<PUBLIC_IP>/httpbin/status/403"
경로/whoami/
이미지traefik/whoami:latest
인스턴스4개 (포트 8082-8085), 라운드 로빈 (무상태)
리소스인스턴스당 CPU 0.25개 / RAM 64 MiB
프레임워크Go
프로젝트github.com/traefik/whoami

whoami는 Traefik의 경량 요청 에코 서버입니다. 오리진 서버가 받는 수신 HTTP 요청의 모든 세부 정보(호스트명, IP 주소, 모든 헤더, 메서드 및 URL)를 표시합니다. 이것은 F5 XC가 올바른 헤더를 주입하고 있는지 확인할 때 가장 중요한 단일 진단 도구입니다.

사용 사례확인 사항
F5 XC 헤더 인젝션 확인X-Forwarded-For, True-Client-IP, X-Volterra-* 헤더
클라이언트 IP 가시성 확인X-Real-IPRemoteAddr
웹 앱 방화벽 (WAF) 오탐 디버그F5 XC 전후 요청 헤더 비교
Bot 방어 태깅 유효성 검사X-Volterra-Bot-Type, X-Volterra-Bot-Verified 헤더
TLS 종료 확인X-Forwarded-Proto가 F5 XC에서 TLS 종료 시 https를 표시
Terminal window
# 기본 요청 -- 오리진 서버가 받는 것을 확인
curl "http://<PUBLIC_IP>/whoami/"
# F5 XC를 통한 요청 시뮬레이션 (주입된 헤더 포함)
curl "http://<PUBLIC_IP>/whoami/" \
-H "X-Forwarded-For: 203.0.113.50" \
-H "True-Client-IP: 203.0.113.50" \
-H "X-Forwarded-Proto: https"

출력 예시:

Hostname: 534c5084e169
IP: 127.0.0.1
RemoteAddr: 172.17.0.1:55118
GET / HTTP/1.1
Host: 20.12.78.159
User-Agent: curl/8.5.0
Accept: */*
True-Client-Ip: 203.0.113.50
X-Forwarded-For: 203.0.113.50, 10.0.0.1
X-Forwarded-Proto: https
X-Real-Ip: 104.219.105.84

DVGA (Damn Vulnerable GraphQL Application)

섹션 제목: “DVGA (Damn Vulnerable GraphQL Application)”
경로/dvga/
이미지dolevf/dvga:latest
인스턴스4개 (포트 5201-5204), ip_hash를 통한 스티키 (인스턴스별 SQLite)
리소스인스턴스당 CPU 0.5개 / RAM 256 MiB
프레임워크Python / Flask / GraphQL
프로젝트github.com/dolevf/Damn-Vulnerable-GraphQL-Application

DVGA는 GraphQL 특정 취약점 테스트를 위해 특별히 제작되었습니다. 대화형 쿼리 탐색을 위한 GraphiQL IDE를 /dvga/에서 제공하고, GraphQL API 엔드포인트를 /dvga/graphql에서 제공합니다. 각 인스턴스는 자체 SQLite 데이터베이스를 사용하므로, ip_hash 스티키 세션이 일관된 상태를 보장합니다.

시나리오카테고리공격 벡터
GraphQL 인젝션API 보안문자열 보간을 통한 악성 쿼리
서비스 거부API 보안깊게 중첩된 쿼리, 배치 쿼리, 리소스 소진
인증 우회API 보안GraphQL을 통한 무단 데이터 접근
정보 노출API 보안스키마 세부 정보를 노출하는 인트로스펙션 쿼리
배치 공격API 보안단일 요청의 여러 작업
Terminal window
# GraphiQL UI (대화형 IDE)
curl -sf "http://<PUBLIC_IP>/dvga/" -o /dev/null -w "%{http_code}"
# 인트로스펙션 쿼리 -- 전체 스키마 열거
curl -s "http://<PUBLIC_IP>/dvga/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"{ __schema { types { name fields { name } } } }"}'
# 붙여넣기 목록 조회 (예제 쿼리)
curl -s "http://<PUBLIC_IP>/dvga/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"{ pastes { title content } }"}'
# 붙여넣기 생성 (뮤테이션)
curl -s "http://<PUBLIC_IP>/dvga/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"mutation { createPaste(title:\"test\", content:\"hello\", public:true) { paste { title } } }"}'

RESTaurant (Damn Vulnerable RESTaurant API Game)

섹션 제목: “RESTaurant (Damn Vulnerable RESTaurant API Game)”
경로/restaurant/
이미지theowni/Damn-Vulnerable-RESTaurant-API-Game에서 커스텀 빌드
인스턴스4개 (포트 8301-8304), 라운드 로빈 (공유 PostgreSQL)
리소스인스턴스당 CPU 0.5개 / RAM 256 MiB
데이터베이스공유 PostgreSQL 15.4 (restaurant-db 컨테이너, CPU 0.5개 / 512 MiB)
프레임워크Python / FastAPI / PostgreSQL
자격 증명admin / password (PostgreSQL)
프로젝트github.com/theowni/Damn-Vulnerable-RESTaurant-API-Game

RESTaurant는 OWASP API Security Top 10 2023을 다루는 게임화된 취약한 REST API입니다. /restaurant/docs에서 자동 Swagger UI 문서와 함께 FastAPI를 사용합니다. 4개의 인스턴스 모두 단일 PostgreSQL 데이터베이스를 공유하므로, 스티키 세션 없이 라운드 로빈 로드 밸런싱이 작동합니다.

시나리오OWASP API Top 10 2023방법
객체 수준 인증 취약점 (BOLA)API1ID 조작으로 다른 사용자의 주문 접근
취약한 인증API2약한 토큰 처리, 자격 증명 스터핑
객체 속성 수준 인증 취약점API3사용자 프로필 필드에 대량 할당
무제한 리소스 소비API4엔드포인트에 속도 제한 없음
기능 수준 인증 취약점 (BFLA)API5일반 사용자로 관리자 엔드포인트 접근
서버 측 요청 위조 (SSRF)API7서버 측 URL 요청 조작
보안 설정 오류API8상세한 오류 메시지, 기본 자격 증명
Terminal window
# Swagger UI
curl -sf "http://<PUBLIC_IP>/restaurant/docs" -o /dev/null -w "%{http_code}"
# OpenAPI 사양
curl -s "http://<PUBLIC_IP>/restaurant/openapi.json" | jq .info
# BOLA -- 다른 사용자의 주문 접근 (인증 후)
curl -s "http://<PUBLIC_IP>/restaurant/orders/1" \
-H "Authorization: Bearer <token>"
# BFLA -- 일반 사용자로 관리자 작업 시도
curl -s -X POST "http://<PUBLIC_IP>/restaurant/admin/users" \
-H "Authorization: Bearer <user_token>" \
-H "Content-Type: application/json"
포트8888 (전용 — 경로 접두사 없음)
이미지crapi/crapi-web, crapi/crapi-identity, crapi/crapi-community, crapi/crapi-workshop, PostgreSQL, MongoDB, MailHog
인스턴스7개 마이크로서비스 (각 단일 인스턴스)
리소스총 CPU ~3.0개 / RAM ~2.0 GiB
프레임워크React SPA + Java/Go/Python 마이크로서비스
프로젝트github.com/OWASP/crAPI

crAPI는 API 보안 테스트를 위한 OWASP 플래그십 프로젝트입니다. React SPA가 API 경로를 하드코딩하고 경로 접두사 뒤에서 제공될 수 없기 때문에 전용 포트(8888)에서 7개의 마이크로서비스로 실행됩니다. NSG는 포트 8888의 인바운드 트래픽을 허용합니다.

MailHog는 crAPI가 발송하는 모든 이메일(계정 확인, 비밀번호 재설정)을 캡처합니다. 포트 18025에서 SSH 터널을 통해 MailHog에 접근합니다.

카테고리취약점
BOLA (객체 수준 인증 취약점)다른 사용자의 차량, 주문 및 보고서 접근
BFLA (기능 수준 인증 취약점)관리자로 권한 상승, 제한된 엔드포인트 접근
대량 할당API를 통해 보호된 필드(역할, 잔액) 수정
SSRF (서버 측 요청 위조)서버 측 URL 가져오기 조작
JWT 조작권한 상승을 위한 JWT 토큰 위조 또는 수정
NoSQL 인젝션MongoDB 기반 엔드포인트에 쿼리 인젝션
과도한 데이터 노출API가 민감한 사용자 데이터 반환
Terminal window
# crAPI 실행 확인
curl -sf "http://<PUBLIC_IP>:8888" -o /dev/null -w "%{http_code}"
# 새 사용자 가입
curl -s -X POST "http://<PUBLIC_IP>:8888/identity/api/auth/signup" \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com","number":"1234567890","password":"Test1234!"}'
# 로그인
curl -s -X POST "http://<PUBLIC_IP>:8888/identity/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"Test1234!"}'
# MailHog 접근 (이메일 인증을 위한 SSH 터널 사용)
# ssh -L 18025:localhost:18025 azureuser@<PUBLIC_IP>
# 그런 다음 브라우저에서 http://localhost:18025 열기
Port 8888 -> crapi-web (React SPA + nginx)
-> crapi-identity (Java, user auth, JWT)
-> crapi-community (Go, forums, posts)
-> crapi-workshop (Python, vehicle service)
-> crapi-postgres (PostgreSQL)
-> crapi-mongo (MongoDB)
-> crapi-mailhog (email capture, port 18025)

애플리케이션 커버리지 매트릭스

섹션 제목: “애플리케이션 커버리지 매트릭스”
데모 사용 사례주요 앱보조 앱
웹 앱 방화벽 (WAF) — SQL 인젝션DVWAJuice Shop
웹 앱 방화벽 (WAF) — XSSDVWAJuice Shop
웹 앱 방화벽 (WAF) — 커맨드 인젝션DVWA
API 보안 — BOLAVAmPI
API 보안 — 인증 우회VAmPIJuice Shop
API 보안 — 데이터 노출VAmPIhttpbin
Bot 표준 방어 — 브루트 포스DVWAJuice Shop
Bot 표준 방어 — 스크래핑Juice Shop
클라이언트 측 방어 — DOM XSSJuice Shop
클라이언트 측 방어 — 저장형 XSSDVWAJuice Shop
클라이언트 측 방어 — 카드 스키머CSD Demo
클라이언트 측 방어 — 폼재킹CSD Demo
클라이언트 측 방어 — 키로거CSD Demo
클라이언트 측 방어 — 크립토마이너CSD Demo
클라이언트 측 방어 — DOM 하이재킹CSD Demo
API 보안 — GraphQL 인젝션DVGA
API 보안 — GraphQL DoSDVGA
API 보안 — OWASP API Top 10 2023RESTaurantcrAPI
API 보안 — BFLARESTaurantcrAPI
API 보안 — 대량 할당crAPIRESTaurant
API 보안 — SSRFcrAPIRESTaurant
API 보안 — JWT 조작crAPI
API 보안 — NoSQL 인젝션crAPI
기본 연결 테스트httpbin
요청 진단whoamihttpbin
헤더 인젝션 확인whoami