WAF 정규화 불일치 사례 분석
이 글은 공개된 원 분석들을 우리 관점에서 다시 쓰고 논평을 더한 정리본입니다. 특정 문장·코드를 그대로 옮기지 않았으며, 자세한 내용은 하단 References의 원문을 참고하세요.
Security · 웹·서버 · 정보정리 [정보성]
웹 방화벽(WAF, Web Application Firewall)을 우회했다는 소식은 특정 제품의 특정 버그처럼 보이지만, 많은 경우 뿌리는 같습니다. 방화벽이 요청을 해석하는 방식과 그 뒤의 애플리케이션이 해석하는 방식이 어긋나는 것입니다. 이 글은 그 어긋남의 핵심 개념인 “정규화(canonicalization) 불일치”를 공개된 1차 자료와 연구를 바탕으로 정리합니다.
새 우회 기법이 나올 때마다 “시그니처를 더 촘촘히 짜면 되지 않나” 싶지만, 실제로는 같은 부류의 우회가 제품과 연도를 바꿔가며 계속 돌아옵니다. 이것은 개별 제품의 실수라기보다, 검사 지점과 실행 지점이 분리된 구조에서 나오는 되풀이되는 현상에 가깝습니다. 아래에서 그 구조를 하나씩 풀어봅니다.
핵심 사실 요약
정규화와 임피던스 불일치
정규화는 데이터를 가장 단순하고 표준적인 형태, 즉 정준형(canonical form)으로 바꾸는 과정입니다. 같은 뜻을 가진 여러 표현을 하나의 기준 형태로 모으는 작업이라고 생각하면 됩니다. OWASP 자료는 완전히 정규화되지 않은 데이터를 근거로 보안이나 인가 결정을 내리면 취약점이 생긴다고 설명합니다.
여기에 WAF 특유의 구조가 겹칩니다. WAF는 대개 역방향 프록시(reverse proxy)로 요청 앞에 서지만, 요청을 완전히 다시 써서 뒤로 넘기지는 않습니다. 그래서 방화벽이 읽은 요청의 모습과 애플리케이션이 최종적으로 실행하는 모습 사이에 틈이 남습니다. ModSecurity와 OWASP 코어 룰셋을 다룬 Ivan Ristić의 글은 이 틈을 임피던스 불일치(impedance mismatch)라고 부릅니다. 전기 회로에서 두 단의 특성이 안 맞아 신호가 새는 것에 빗댄 표현입니다.
독립 분석(Cyshield)은 이 점을 더 넓혀서 설명합니다. 웹 애플리케이션은 하나의 처리 단위가 아니라, 같은 요청을 저마다 다르게 읽는 계층 부품들의 사슬이라는 것입니다. 이 사슬에서 임의의 두 부품이 같은 요청을 다르게 해석하는 지점이 곧 악용될 수 있는 틈이 됩니다.
빈틈 — 순서가 바뀌면 검사가 헛돈다
정규화와 검증의 순서가 문제의 중심입니다. OWASP는 “정규화를 먼저 하고, 검증을 나중에” 하라고 권고합니다. 모든 사용자 입력을 정한 정준형으로 바꾼 뒤에 인가나 보안 판단을 수행하라는 것입니다.
MITRE는 이 순서가 뒤집힌 안티패턴을 하나의 약점 유형으로 분류해 두었습니다. CWE-180 “Incorrect Behavior Order: Validate Before Canonicalize” 입니다. 입력이 정규화되기 전에 검증하면, 정규화를 거친 뒤에야 비로소 위험해지는 데이터를 놓치게 됩니다. 검사 시점에는 멀쩡해 보이던 문자열이, 표준 형태로 펼쳐진 다음에 악성으로 바뀌는 것입니다.
MITRE가 드는 교과서적 예시는 경로 문자열입니다. /safe_dir/../ 같은 입력은 검증을 통과하지만, 정규화하면 / 가 되어 상위 디렉터리 접근을 노출합니다. 검사기는 “안전한 디렉터리 안”이라고 판단했는데, 정규화가 그 판단의 전제를 지워버린 셈입니다.
MITRE는 완화책으로 정규화 이후에 검증할 것, 그리고 같은 입력을 두 번 디코딩하지 말 것을 함께 권고합니다. 이 이중 디코딩 문제는 CWE-174(Double Decoding) 로 별도 분류돼 있습니다. 한 번 검사를 통과한 입력을 뒤에서 다시 디코딩하면, 걸러졌어야 할 위험 입력이 되살아나 허용 목록(allowlist)을 우회할 수 있습니다.
메커니즘 — 인코딩 틈과 파싱 틈
틈이 벌어지는 자리는 크게 두 갈래입니다.
첫째, 인코딩 차이. 많은 WAF가 URL 디코딩 전에 패턴을 맞추거나, 백엔드와 다른 방식으로 디코딩합니다. 그래서 방화벽이 자기 기준으로 디코딩한 뒤에는 정상으로 보이지만, 애플리케이션이 디코딩을 마치면 악성 문자열이 복원됩니다. 이중 인코딩(double encoding)은 두 번째 정규화 틈을 만듭니다. 한 단계 인코딩만 인지하는 필터는 1차 디코딩된 형태만 검사하고, 백엔드가 2차로 복원하는 단계를 보지 못할 수 있습니다. 유니코드나 오버롱(overlong) 인코딩도 같은 계열입니다. 하나의 문자를 여러 바이트 표현으로 나타낼 수 있어서, ASCII 시그니처에만 기댄 검사를 비켜갑니다.
하나의 문자를 여러 방식으로 쓸 수 있다는 점만 짚으면 충분합니다. 특정 오버롱 바이트열이 지금도 어떤 제품에서 통하는지는 제품·버전에 따라 다르므로 일반화할 수 없습니다. ⚠️미확인
개념용 설명이며, 작동하는 우회 문자열이 아닙니다.
둘째, 파싱 구조 차이. 더 근본적인 틈은 단순한 인코딩을 넘어 HTTP 요청의 구조를 파싱하는 방식에서 나옵니다. 학술 연구 WAFFLED는 우회의 상당수가 페이로드 난독화가 아니라 요청 구조 파싱의 불일치에서 비롯됨을 보였습니다. 페이로드는 그대로 두고 요청의 구성 요소만 변형해, 방화벽은 요청을 잘못 파싱하고 백엔드는 정상적으로 실행하게 만드는 식입니다.
WAFFLED의 관찰에서 드러나는 원인은, 우리가 정리하자면 대략 네 갈래로 묶을 수 있습니다. (1) WAF와 프레임워크가 같은 요청에 서로 다른 파싱 규칙을 적용하는 것, (2) RFC 자체의 모호함이 복수의 유효한 해석을 허용하는 것, (3) 폐기됐거나 선택적인 기능을 부품마다 다르게 처리하는 것, (4) multipart·XML·JSON 같은 중첩 구조의 복잡성입니다. 이 네 갈래는 논문이 명시한 분류 체계가 아니라, 논문에 흩어진 관찰을 우리가 묶은 재구성입니다. ⚠️미확인
구체적인 사례 하나는 멀티파트(multipart) 파싱입니다. Ivan Ristić의 글에 따르면, PHP는 작은따옴표를 문자열의 임의 위치에서 허용하지만 ModSecurity는 첫 위치에만 올 것으로 기대했습니다. 그 결과 방화벽은 그 부분을 파일 업로드로, PHP는 일반 파라미터로 해석해 룰셋이 비켜갔습니다. 두 부품의 기대가 미세하게 다른 지점이 그대로 통로가 된 것입니다.
왜 반복되는가 — 비대칭이 구조에 박혀 있다
더 나은 시그니처로 이 문제를 끝내기 어려운 이유는 수(數)의 비대칭 때문입니다. Cyshield의 분석은, 같은 악성 의도를 표현하는 방법의 공간은 인코딩 변형·구조 변형·의미 등가·포맷 전환을 조합하며 지수적으로 늘어나는 반면, 시그니처 라이브러리는 선형으로만 늘어난다고 지적합니다. 시간이 지나면 변형의 공간이 룰셋을 추월합니다. 게다가 방어자는 모든 변형을 막아야 하지만 공격자는 한 번만 통과시키면 됩니다.
여기에 더해, 시그니처 기반 탐지에는 더 깊은 한계가 있습니다. ByteHide의 정리처럼, 시그니처는 철자와 패턴을 맞출 뿐 입력의 “의미”를 추론하지 못합니다. 그래서 의미는 같되 표현이 다른 입력 앞에서 번번이 새는 것입니다.
이 그림은 우리가 다른 글에서 다룬 파서 불일치(parser differential) 계열과 같은 뿌리입니다. 요청 스머글링이나 XXE(XML External Entity)처럼, 두 부품의 해석을 벌려 그 틈으로 밀어 넣는 공격들이 전부 같은 사고방식 위에 있습니다. “검사하는 쪽이 본 것”과 “실행하는 쪽이 본 것”이 다를 때 보안 경계가 허물어진다는 원리입니다.
대응방안 — 틈을 줄이는 쪽으로
WAF는 특정 제품의 버그가 아니라 구조에서 오는 문제이므로, 대응도 틈 자체를 줄이는 방향이 기본입니다.
- 순서를 지킵니다. OWASP 권고대로 정규화를 먼저, 검증을 나중에 합니다. 보안 판단은 디코딩이 끝난 정준형 위에서 내립니다.
- 이중 디코딩을 피합니다. MITRE가 CWE-174로 지적한 대로, 한 번 검사한 입력을 뒤에서 다시 디코딩하지 않도록 경로를 정리합니다.
- 해석을 한곳으로 모읍니다. 방화벽과 백엔드가 같은 요청을 같은 규칙으로 파싱하도록 맞출수록 틈이 줄어듭니다. WAF를 유일한 방어선이 아니라 다층 방어의 한 겹으로 두는 것이 안전합니다.
마무리
정규화 불일치로 생긴 한 틈은 패치로 막힙니다. 하지만 검사 지점과 실행 지점을 벌리는 이 사고방식은 인코딩에서, 멀티파트에서, 다음에는 또 다른 포맷에서 되돌아옵니다. 그래서 우리는 개별 우회 기법의 목록이 아니라, 왜 이 부류가 반복되는지의 원리를 남겨둡니다.
References / 참고자료
이 글은 아래 원 분석들을 우리 관점에서 다시 쓰고 논평을 더한 정리본입니다. 특정 문장·코드를 그대로 옮기지 않았으며, 자세한 내용은 원문을 참고하세요.
- MITRE, “CWE-180: Incorrect Behavior Order: Validate Before Canonicalize” — 정규화 전 검증 안티패턴과
/safe_dir/../예시, 이중 디코딩(CWE-174) 관계의 1차 분류. https://cwe.mitre.org/data/definitions/180.html - OWASP, “Canonicalization, locale and Unicode” (OWASP Wiki) — 정규화의 정의, “정규화 먼저·검증 나중” 권고, 이중 인코딩과 오버롱 인코딩 개념. https://wiki.owasp.org/index.php/Canoncalization,_locale_and_Unicode
- Ivan Ristić, “ModSecurity and ModSecurity Core Rule Set Multipart Bypasses” (2012) — 임피던스 불일치 개념의 원전과 멀티파트 파싱 사례. https://blog.ivanristic.com/2012/06/modsecurity-and-modsecurity-core-rule-set-multipart-bypasses.html
- S. A. Akhavani 외, “WAFFLED: Exploiting Parsing Discrepancies to Bypass Web Application Firewalls” (arXiv:2503.10846) — 파싱 불일치 기반 우회의 경험적 발굴과 여러 WAF 대상 대규모 검증. 본문의 “네 갈래” 묶음은 논문이 명시한 4분류 taxonomy가 아니라 논문에 흩어진 관찰을 우리가 재구성한 것 ⚠️미확인. 공개/개정 연도는 ⚠️미확인(arXiv 식별자는 2025년 3월 제출을 시사하나 재확인 필요), 우회 건수의 세부 분배도 원문 표 ⚠️미확인. https://arxiv.org/html/2503.10846v4
- Ahmed Maghawry (Cyshield Seclab), “WAF Evasion 101: How Attackers Bypass Security Gates” — 계층 부품의 해석 차이와 시그니처 비대칭 논증. https://seclab.cyshield.com/posts/waf-evasion-101-how-attackers-bypass-security-gates/
- NHIMG, “Double Encoding” (Glossary) — 이중 인코딩이 계층별 해석 차이를 만드는 원리 보강. 단, 해당 페이지는 접근 차단(HTTP 403)으로 본문 내용 대조가 안 돼 실재·주장 뒷받침 ⚠️미확인. 이중 인코딩 개념 자체는 위 Ref#1(CWE)·#2(OWASP)로 이미 뒷받침됨. https://nhimg.org/glossary/double-encoding/
- ByteHide, “Why WAFs Fail: Bypass Techniques and Runtime Alternatives” (2026-03-04) — 시그니처가 패턴은 맞추되 의미를 추론하지 못하는 한계 보강. https://bytehide.com/blog/web-application-firewall-bypass