home
SAA-C03

[security] AWS WAF

정상 요청처럼 위장한 SQL 인젝션과 XSS를, WAF가 실제로 어떻게 걸러내는지 뜯어봅니다.

One-Line Summary

AWS WAFHTTP/HTTPS 요청(L7)을 내용까지 뜯어보고 SQL 인젝션·XSS·악성 봇·특정 국가/IP·과도한 요청 같은 웹 공격을 규칙(rule)으로 필터링하는 애플리케이션 계층 방화벽이다. CloudFront / ALB / API Gateway / AppSync / Cognito에 붙는다. 시험에서는 L7 웹 공격 차단 / 관리형 규칙(Managed Rules) / Rate-based 규칙 / 지리·IP 차단 / WAF vs Shield vs Network Firewall vs SG·NACL / 왜 L4는 못 막나 가 핵심이다.

뭔지 (What / Why)

SG·NACL은 IP·포트(L3/L4) 수준에서만 판단한다. "443 포트로 들어오는 HTTPS"는 정상 트래픽처럼 보이지만, 그 안의 요청 본문에 ' OR 1=1-- 같은 SQL 인젝션 페이로드가 들어있을 수 있다. SG·NACL은 이걸 볼 수 없다 — 포트와 IP만 맞으면 통과시킨다.

WAF는 그 HTTP 요청의 내용물(URL 경로, 헤더, 쿼리스트링, 바디, 쿠키, HTTP 메서드)을 검사해서 "이건 공격 패턴이다" 하고 막거나(Block), 통과시키거나(Allow), 세거나(Count), 캡차/챌린지를 띄운다.

클라이언트 요청 (HTTPS 443)
   │  헤더 / URI / 쿼리 / 바디 / 쿠키 …
   ▼
[AWS WAF]  ← 요청 "내용"을 규칙과 대조 (L7)
   │  Allow / Block / Count / CAPTCHA / Challenge
   ▼
[CloudFront / ALB / API Gateway / AppSync / Cognito]
   ▼
백엔드(EC2/Lambda/…)

핵심: SG·NACL은 "누가·어느 포트로" 왔는지를 보고, **WAF는 "무엇을 요청하는지(내용)"**를 본다.

왜 L7은 막는데 L4는 못 막나 (사용자 질문 — 반드시 이해)

이건 WAF가 어디에 붙어서, 무엇을 볼 수 있느냐의 문제다.

1) WAF는 L7 종단(HTTP 리버스 프록시) 위에서 동작한다

WAF는 raw 패킷을 보는 장치가 아니라, HTTP 요청이 이미 조립·복호화된 지점(CloudFront, ALB, API Gateway)에 붙는다. 이 지점에서는 이미:

  • TCP 핸드셰이크가 끝나 연결이 성립되어 있고,
  • TLS가 복호화되어 있으며,
  • 흩어진 TCP 세그먼트가 하나의 완결된 HTTP 요청으로 재조립되어 있다.

즉 WAF가 보는 입력 단위는 "패킷"이 아니라 **"HTTP 요청 하나"**다. 그래서 URI·헤더·바디 같은 L7 필드를 검사할 수 있다.

[TCP/IP 패킷들] → (LB/CloudFront가 TLS 복호화 + HTTP 재조립) → [완성된 HTTP 요청] → [WAF가 검사]
   L3/L4 영역                                                        L7 영역 ◀── WAF는 여기부터

2) L4 공격은 "요청 내용"이 아니라 "연결·패킷 자체"라서 WAF의 검사 대상이 될 수 없다

L4(전송 계층) 공격의 대표는 SYN Flood, UDP Flood, 볼류메트릭 DDoS다. 이들의 특징:

  • HTTP 요청을 완성하지 않는다. 예: SYN Flood은 TCP 핸드셰이크의 SYN만 쏟아붓고 연결을 완성하지 않는다 → 애초에 "HTTP 요청"이 만들어지지 않으니 WAF까지 도달하지 못한다.
  • 페이로드에 악의가 있는 게 아니라, 물량·연결 상태 자체가 공격이다. WAF는 "이 요청 내용이 나쁜가?"를 판단하는 도구지, "초당 수백만 SYN 패킷"을 흡수하는 장치가 아니다.
  • WAF가 붙는 지점(L7 프록시)에 트래픽이 도달하기 전에, 네트워크·전송 계층에서 이미 처리(흡수/차단)되어야 한다.

비유: WAF는 건물 입구에서 방문객이 들고 온 가방 속 내용물을 검사하는 보안요원이다. 그런데 L4 DDoS는 "수백만 명이 문 앞에 몰려와 문을 못 열게 하는" 상황 — 가방을 열어볼 문제가 아니라 **군중을 통제(용량/네트워크)**해야 하는 문제다.

3) 그럼 L3/L4는 누가 막나 — 계층별 분담

계층공격 예시담당
L3/L4 (네트워크·전송)SYN/UDP Flood, 볼류메트릭 DDoS, IP 스푸핑Shield (Standard/Advanced), Network Firewall, NACL
L7 (애플리케이션)SQLi, XSS, 악성 봇, HTTP Flood, 나쁜 요청WAF
  • Shield Standard(무료·자동): CloudFront/Route 53/ELB 앞에서 흔한 L3/L4 DDoS를 자동 완화.
  • Shield Advanced(유료): 대규모 DDoS 방어 + DDoS 대응팀(DRT) + 요금 급증 보호.
  • WAF: L7 — Shield가 못 보는 "요청 내용"과 L7 HTTP Flood(rate-based) 담당.

주의: **HTTP Flood(L7 DDoS)**는 WAF의 Rate-based rule로 막는다. "DDoS니까 무조건 Shield"가 아니라, L7 요청 폭주는 WAF rate-limit, L3/L4 볼류메트릭은 Shield로 나뉜다.

핵심 구성 요소 (빈출)

요소의미
Web ACLWAF의 최상위 컨테이너. 규칙들을 담아 리소스(CloudFront/ALB 등)에 연결
Rule검사 조건 + 동작(Allow/Block/Count/CAPTCHA/Challenge)
Rule Group규칙 묶음(재사용). Managed 또는 직접 생성
Managed RulesAWS·마켓플레이스가 관리하는 사전 정의 규칙 세트(자동 업데이트)
Statement(조건)IP set / geo match / string·regex match / SQLi / XSS / size / rate 등
Default action어떤 규칙에도 안 걸린 요청의 기본 처리(Allow 또는 Block)

Rule 동작(Action)

Action의미용도
Allow통과명시적 허용
Block차단(403 반환)공격 차단
Count차단 안 하고 카운트만규칙 배포 전 테스트/튜닝(오탐 확인)
CAPTCHA퍼즐 요구사람 여부 확인, 봇 차단
Challenge브라우저에 조용한 챌린지(JS)자동화 봇 차단(사용자 개입 최소)

실무 팁: 새 규칙은 먼저 Count로 배포해 오탐을 관찰하고, 안전 확인 후 Block으로 전환한다. (시험에도 "정상 트래픽 영향 없이 규칙 검증" → Count 로 나온다.)

규칙 조건(Statement) 종류 — 무엇을 검사하나

조건막는 것
IP set match특정 IP/CIDR 허용·차단(알려진 악성 IP)
Geo match국가 단위 허용·차단(지리 제한)
String / Regex matchURI·헤더·쿼리·바디의 특정 문자열/패턴
SQLi matchSQL 인젝션 패턴
XSS match크로스사이트 스크립팅 패턴
Size constraint과도하게 큰 바디/헤더(버퍼 오버플로·남용)
Rate-basedIP당 5분 슬라이딩 윈도 요청 수 초과 시 차단(L7 DDoS/브루트포스)

Rate-based rule (빈출 — L7 폭주 방어)

특정 IP가 5분(rolling) 동안 정해진 임계치를 넘으면 해당 IP를 임시 차단한다.

예: "IP 하나가 5분 내 2000 요청 초과 → Block"
   → HTTP Flood, 로그인 브루트포스, 스크래핑 방어
  • 임계치 아래로 떨어지면 자동 해제. IP·헤더·쿠키 등 기준으로 세분화 가능.
  • "특정 IP의 과도한 요청/브루트포스/스크래핑" = Rate-based rule.

탐지·차단은 실제로 어떻게 일어나나 (메커니즘 심화)

"WAF가 SQLi를 막는다"는 말의 실제 동작은 4단계로 일어난다. 규칙 하나는 다음을 정의한다:

① 어디를 볼까 (Inspection component)  →  ② 어떻게 정규화할까 (Text transformation)
   →  ③ 무엇과 매칭할까 (Match statement)  →  ④ 걸리면 뭘 할까 (Action)

단계 ①: 요청의 "어느 부분"을 볼지 고른다 (Inspection component)

WAF는 요청 전체를 뭉뚱그려 보지 않는다. 검사 대상 컴포넌트를 명시적으로 지정한다.

컴포넌트
URI path/products/search
Query string / 개별 query 인자?id=10id
Header (단일/전체)User-Agent, Cookie
Body (전체/JSON 특정 필드)POST 본문, {"user":"..."}user
HTTP methodGET / POST

핵심: SQLi는 보통 query 인자·body에, 봇/스캐너는 User-Agent 헤더에, 경로 탐색은 URI에 들어온다. 그래서 규칙마다 "볼 곳"이 다르다.

바디 검사 한계 (빈출·실무 함정):

  • WAF는 바디 앞부분 일부만 검사한다 — 기본 ALB/API Gateway 8 KB, CloudFront 16 KB(설정으로 상향 가능, CloudFront는 최대 64 KB).
  • 그 한계를 넘는 부분은 oversize handling 옵션으로 처리: Continue(넘는 부분 무시하고 계속) / Match(초과 자체를 매치로) / NoMatch.
  • 함정: 공격 페이로드를 바디 뒷부분(8KB 이후)에 숨기면 기본 설정에선 검사 밖 → 큰 바디를 다루면 한계·oversize 처리를 반드시 설계.

단계 ②: 인코딩 회피를 무력화한다 (Text Transformation) — 가장 중요

공격자는 탐지를 피하려고 페이로드를 인코딩·변형한다. 그래서 WAF는 매칭 전에 입력을 정규화(normalize)한다. 이게 없으면 단순 문자열 매칭은 쉽게 우회당한다.

공격자가 보내는 것:  %27%20OR%201%3D1--        (URL 인코딩된 ' OR 1=1--)
                    ' OR 1=1--   ← URL_DECODE 변환 후 원형이 드러남 → 매칭됨

주요 변환(규칙에 순서대로 여러 개 적용 가능):

Transformation하는 일막는 회피
URL_DECODE%27'URL 인코딩 회피
HTML_ENTITY_DECODE&lt;<, &#39;'HTML 엔티티 회피
LOWERCASESeLeCtselect대소문자 섞기 회피
COMPRESS_WHITE_SPACE공백 다중→단일OR/**/1=1류 공백 조작
CMD_LINE셸 메타문자 정규화명령어 인젝션 회피
BASE64_DECODEbase64 해제인코딩 은닉

시험/실무 핵심: "정규 표현식/문자열 규칙이 인코딩된 공격을 못 잡는다" → Text Transformation을 규칙에 추가해 정규화 후 매칭. WAF가 회피에 강한 이유가 바로 이 단계다.

단계 ③: 무엇과 대조하나 — SQLi 탐지는 "키워드 블랙리스트"가 아니다

여기가 사용자가 궁금해한 **"SQL Injection을 실제로 어떻게 막나"**의 핵심이다.

순진한 방식은 "select", "union" 같은 키워드를 블랙리스트로 막는 것인데, 이건 두 가지로 실패한다:

  • 오탐: 정상 검색어 "I select the best union representative"도 막아버림.
  • 미탐: SeL/**/eCT, 인코딩 등으로 쉽게 우회.

그래서 WAF의 SQLi match statement는 단어를 세는 게 아니라, 정규화된 입력을 SQL 문법 구조로 해석해 "SQL 코드로 동작 가능한가"를 판단한다. 즉 **"이 입력이 SQL 구문처럼 동작하는가"**를 본다.

정상 검색:  keyword = "red shoes"
   → 토큰화하면 그냥 문자열. SQL 구문 아님 → 통과

공격:  id = "10 OR 1=1--"
   → 토큰화: [숫자][논리연산자 OR][비교식 1=1][주석 --]
   → "값이 들어갈 자리에 항상 참인 조건 + 주석으로 뒷부분 무력화" = 전형적 SQLi 구조
   → Block

탐지되는 대표 구조:

  • Tautology(항상 참): OR 1=1, OR 'a'='a'
  • 주석으로 원 쿼리 절단: --, #, /* */
  • UNION 기반 데이터 추출: UNION SELECT ...
  • 스택 쿼리·서브쿼리 삽입: ; DROP TABLE ...

정리: WAF의 SQLi 차단 = "검사 위치 지정 → 인코딩 정규화 → 입력을 SQL 문법으로 파싱해 공격 구조인지 판별 → Block". 단순 단어 매칭이 아니라 구문 해석 기반이라 회피에 강하고 오탐이 적다.

(XSS도 같은 원리 — <script>, onerror=, javascript: 같은 HTML/JS 실행 구조를 정규화 후 파싱해 판별한다.)

단계 ④: 규칙 평가 순서와 Action의 종결성 (자주 틀림)

Web ACL 안의 규칙들은 priority 번호 오름차순으로 평가되며, Action에 따라 평가가 **거기서 끝나느냐(terminating)**가 갈린다.

Action종결성동작
Allow종결즉시 허용, 이후 규칙 안 봄
Block종결즉시 차단(403), 이후 규칙 안 봄
Count비종결카운트만 하고 다음 규칙 계속 평가
CAPTCHA / Challenge조건부 종결토큰 유효하면 통과, 아니면 챌린지 띄우고 종결
priority 0:  IP set (사내 IP) → Allow      [종결] 사내는 여기서 통과
priority 1:  Rate-based                    [초과 시 Block-종결]
priority 2:  Managed SQLi rule → Block     [SQLi면 여기서 차단]
priority 3:  Bot Control
default action:  아무 규칙에도 안 걸리면 Allow(또는 Block)
  • Count가 비종결이라는 점이 "Count로 테스트" 패턴의 핵심 — Block으로 안 끊고 로그만 쌓으며 뒤 규칙도 계속 평가하니 오탐을 안전하게 관찰할 수 있다.

요청 하나가 WAF를 통과하는 전체 흐름 (종합 예시)

POST /login?next=%27+OR+1%3D1--   Host: shop.example
Body: {"user":"admin","pass":"' OR '1'='1"}

1) CloudFront/ALB가 TLS 복호화 + HTTP 재조립  → 완성된 요청
2) [priority 0] IP set(사내) 매칭? → 아니오, 다음
3) [priority 1] Rate-based: 이 IP 5분 내 임계 이하 → 통과
4) [priority 2] SQLi rule:
      - 컴포넌트: query 'next' + body 'pass'
      - Text transform: URL_DECODE → next = ' OR 1=1--
      - SQL 파싱: tautology + 주석 구조 감지 → 매칭!
      - Action: Block(종결) → 403 반환, 백엔드로 안 감
5) 로그: 어떤 규칙이 막았는지 Firehose→S3/CloudWatch에 기록

Managed Rules (빈출 — 실무 기본값)

직접 SQLi/XSS 규칙을 짜지 않고, AWS가 관리·업데이트하는 규칙 세트를 붙인다.

대표 Managed Rule Group막는 것
Core rule set (CRS)OWASP 일반 위협(광범위 기본기)
Known bad inputs알려진 악성 페이로드
SQL databaseSQL 인젝션
Linux / POSIX / Windows OSOS 명령어 인젝션
IP reputation (Amazon)평판 나쁜 IP·봇넷
Bot Control자동화 봇 탐지·관리(스크래퍼, 스캐너)
Account Takeover Prevention (ATP)크리덴셜 스터핑·계정 탈취
Fraud Control / Account Creation (ACFP)가짜 계정 대량 생성 방지

시험 트리거: "관리 부담 없이 OWASP Top 10 / SQLi·XSS를 막고 싶다" → AWS Managed Rules. "봇/스크래퍼 차단" → Bot Control.

어디에 붙나 (통합 지점) — 자주 틀림

붙일 수 있음못 붙음
CloudFront (글로벌 엣지)EC2에 직접
Application Load Balancer (ALB)NLB (L4라서)
API Gateway (REST)일반 TCP 서비스
AppSync (GraphQL)
Cognito User Pool
App Runner / Verified Access

핵심 포인트:

  • NLB에는 WAF를 못 붙인다. NLB는 L4(TCP/UDP)라서 검사할 HTTP 요청이 없다 → 필요하면 앞단에 ALB나 CloudFront를 두고 거기에 WAF.
  • CloudFront에 붙이면 공격을 엣지에서(사용자 가까이) 조기 차단 → 오리진 부하·지연 감소. 글로벌 방어 시 유리.
  • ALB에 붙이면 리전 단위. 오리진 직전 방어.

실무 활용 사례

사례 1. OWASP 공격 차단 (SQLi/XSS)

  • ALB나 CloudFront에 Web ACL 붙이고 Managed Core rule set + SQL database rule 적용 → 코드 수정 없이 인젝션·XSS 방어.

사례 2. 로그인 브루트포스·스크래핑 방어

  • Rate-based rule(IP당 5분 임계치) + Bot Control → 자동화 폭주 IP 차단, 정상 사용자 영향 최소.

사례 3. 지리적 규제·라이선스

  • Geo match로 서비스 불가 국가 차단, 또는 특정 국가만 허용(allow-list).

사례 4. 알려진 악성 IP 즉시 차단

  • IP set에 넣어 Block. (자동화하려면 IP set을 Lambda/보안 피드로 갱신.)

사례 5. CloudFront + WAF로 엣지 방어

  • 정적/동적 사이트를 CloudFront 뒤에 두고 WAF를 CloudFront에 연결 → 오리진 도달 전 엣지에서 L7 공격 차단, 캐시로 성능까지.

사례 6. 로깅·가시성

  • Web ACL 로그를 Kinesis Data Firehose → S3 / CloudWatch Logs로 보내 어떤 규칙이 무엇을 막았는지 분석·튜닝.

WAF vs Shield vs Network Firewall vs SG·NACL (핵심 비교)

서비스계층무엇을위치
WAFL7HTTP 요청 내용(SQLi/XSS/봇/rate)CloudFront/ALB/API GW
Shield StandardL3/L4흔한 볼류메트릭 DDoS(자동·무료)엣지(CloudFront/R53/ELB)
Shield AdvancedL3/L4(+L7 연동)대규모 DDoS + DRT + 요금보호엣지·리전
Network FirewallL3–L7(VPC)VPC 전체 트래픽 필터·IDS/IPSVPC 경계
Security GroupL3/L4ENI 단위 stateful allow인스턴스
NACLL3/L4서브넷 stateless allow/deny서브넷

한 줄 정리: 요청 내용(L7 웹공격) = WAF, 볼류메트릭 DDoS(L3/L4) = Shield, VPC 전반 네트워크 필터·IPS = Network Firewall, IP·포트 접근제어 = SG/NACL.

Common Wrong Directions

오답 방향왜 부족한가
SG/NACL로 SQLi·XSS를 막으려 함L3/L4라 요청 내용을 못 봄WAF
L3/L4 볼류메트릭 DDoS를 WAF로WAF는 L7 → Shield
L7 HTTP Flood를 무조건 Shield로요청 폭주는 WAF Rate-based rule
NLB에 WAF 붙이기NLB는 L4 → ALB/CloudFront 앞단에 WAF
WAF를 EC2에 직접통합 리소스(CloudFront/ALB/API GW)에만
새 규칙을 바로 Block으로 전개오탐 위험 → 먼저 Count(비종결)로 검증
SQLi 규칙을 직접 다 작성AWS Managed Rules로 관리부담 절감
특정 국가 차단을 앱 코드로Geo match가 정답
인코딩된 공격(%27, &lt;)이 규칙을 통과Text Transformation(URL/HTML decode 등)으로 정규화 후 매칭
SQLi를 키워드 블랙리스트로 막으려 함WAF는 SQL 구문 파싱 기반 → 회피·오탐에 강함
큰 POST 바디 뒤쪽 페이로드가 안 잡힘바디는 앞부분(8/16 KB)만 검사 → 한계 상향·oversize handling 설계

Exam Triggers

문제에서 이런 표현이 나오면떠올릴 것
"block SQL injection / XSS / OWASP"WAF (Managed Rules)
"filter HTTP requests by content/URI/header"WAF
"one IP sends too many requests / brute force / scraping"WAF Rate-based rule
"block/allow specific countries"WAF Geo match
"block malicious IP list at L7"WAF IP set
"protect against bots / credential stuffing"WAF Bot Control / ATP
"test a rule without impacting traffic"Count action (비종결)
"attackers evade rules with URL/HTML encoding"Text Transformation
"inspect large request bodies fully"바디 검사 한계 상향 + oversize handling
"large-scale volumetric DDoS (L3/L4)"Shield (Advanced)
"L7 HTTP flood"WAF Rate-based (+ Shield Advanced)
"protect a service behind NLB with WAF"앞에 ALB/CloudFront 두고 WAF
"filter all VPC traffic / IDS-IPS"Network Firewall
"block attacks at the edge, close to users"CloudFront + WAF

Memory Sentence

WAF는 CloudFront/ALB/API GW에 붙어 **HTTP 요청 내용(L7)**을 검사해 SQLi·XSS·봇·지리·rate를 Allow/Block/Count/CAPTCHA로 처리한다. L4(SYN/UDP flood)는 애초에 HTTP 요청이 안 되니 WAF 대상이 아니라 Shield가 막고, L7 요청 폭주는 WAF Rate-based rule로 막는다. 관리부담은 Managed Rules, 오탐 검증은 Count, NLB엔 못 붙으니 앞에 ALB/CloudFront.

References

댓글

아직 댓글이 없습니다.