CS

[CS] 더블 인코딩

kw0n笑 2026. 5. 2. 01:17

 

XSS filtering 취약점 공격 방어 시나리오:

    client → WAF → 어플리케이션 환경에서 WAF가 요청 검증해서 XSS 공격 코드 차단

 

※ WAF: Web Application Firewall, 웹 방화벽

 

 

1. 시나리오

APP은 WAF를 통과한 데이터를 받아 작업 수행한다. 

⇒ WAF는 전달 받은 데이터를 다시 디코딩해서는 안 됨, 그러면 오히려 공격자가 더블 인코딩으로 웹 방화벽의 검증을 쉽게 우회함

<script>(내용)</script>

// %253Csript%253E (내용을 더블 인코딩 한 값)
// 웹 방화벽이 해당 데이터를 디코딩 후 검증 -> %3Csript%3E(내용을 한 번 인코딩)-> 음 안전하네
// app에서 해당 데이터를 다시 디코딩해서 <script> %3Csript%3E을 게시판 DB에 저장, 검증 후 디코딩 발생
// 희생자가 해당 게시글 읽으면 XSS가 발생하여 악성 자바스크립트 코드 실행

 

검사가 미흡한 php 예시

<?php

$query = $_GET["query"]; // PHP는 GET, POST하고 자동으로 디코딩함

if (stripos($query, "<script>") !== FALSE) {
    header("HTTP/1.1 403 Forbidden");
    die("XSS attempt detected: " . htmlspecialchars($query, ENT_QUOTES|ENT_HTML5, "UTF-8"));
}

...

$searchQuery = urldecode($_GET["query"]); // 한 번 더 디코딩(urldecodes)

?>

<h1>Search results for: <?php echo $searchQuery; ?></h1>

  아래의 php 코드를 보면 디코딩이 두 번 이루어짐을 알 수 있다. 

POST /search?query=%3Cscript%3Ealert(document.cookie)%3C/script%3E HTTP/1.1

if (stripos($query, "<script>") !== FALSE)

...
-----
HTTP/1.1 403 Forbidden
XSS attempt detected: &lt;script&gt;alert(document.cookie)&lt;/script&gt;]

// 공격 실패

POST /search?query=%253Cscript%253Ealert(document.cookie)%253C/script%253E HTTP/1.1
...
-----
HTTP/1.1 200 OK
<h1>Search results for: <script>alert(document.cookie)</script></h1>

// 공격 성공

  위의 경우엔 (내용)을 한번만 인코딩하였으므로 두 번째 디코딩에서 필터링된다. 그러나 아래의 경우에서는 (내용)을 두번 디코딩하게 되어 결과적으로 페이로드를 실행하게 되어 공격이 성공한다.

 

2. 방어 방법

  HTML entity encoding(출력 시 인코딩)은 HTML 정규화의 반대 과정으로 브라우저가 정규화를 통해 코드를 실행하지 못하도록, 의도적으로 문자를 뭉개서 단순 텍스트로 보이게 만드는 방어 과정이다. 서버에 어떤 값이 저장되어 있든 브라우저에 뿌려줄 때 <를 &lt;로 바꿔서 출력하면 브라우저는 이를 코드로 실행하지 않고 단순한 문자로 인식한다. 

 

  브라우저는 HTML 문서를 읽을 때 두 가지 모드로 작동합니다.

  1. 실행 모드 (Parsing Tags): <script>를 만나면 자바스크립트 코드로서 실행
  2. 출력 모드 (Rendering Text): &lt;script&gt;를 만나면 화면에 <script>라고 출력하라는 의미구나 생각

 해결법: $searchQuery를 출력할 때 htmlspecialchars()를 사용한다.

 

  만약 공격자가 <script>alert(1)</script>라는 값을 입력햇을 때, 서버가 htmlspecialchars()를 써서 보내준다면 서버(php)는 공격자가 보낸 데이터를 받자마자 바로 화면에 뿌리지 않고, htmlspecialchars()에 집어 넣는다.

 

구분 서버가 브라우저에 보내는 코드 (Source) 브라우저가 사용자에게 보여주는 화면 (View) 스크립트 실행 여부
인코딩 안 함 <h1><script>alert(1)</script></h1> (알림창이 뜸) 실행됨 (위험)
인코딩 함 <h1>&lt;script&gt;alert(1)&lt;/script&gt;</h1> <script>alert(1)</script> 실행 안 됨 (안전)