[php 웹보안] 이중 인코딩( Double encoding) 공격 방법과 대책
- URL 더블 인코딩(Double URI-encoding) 공격과 방어 방법
    - URL Encoded Attacks and Prevention(Defence)
//------------------------------------- 
< 디렉토리 순회 공격 (Directory Traversal , Path Traversal ) > 
    - 예기치 않은 경로의 파일 읽기
<?php
// 이미 자동으로 디코딩된 상태(1차 디코딩) , 
// 이중인코딩 입력시 :  %252F  =>  %2F 로 변환되어 들어옴
$path0 = $path = $_GET["file"] ?? '';
// 보안 검사 : ../ 가 있는지 검사
// 하지만 / 가 %2F 로 변경되어 있는 상태라서 검사에 적용 안됨
if (strstr($path, "../") or strstr($path, "..\\")) {
    exit("Directory traversal attempt detected.");
}
// 사용자 입력 디코딩(코드상으로는 처음이지만, 실제는 2차 디코딩)
// 공격 코드가 완성됨
$path = urldecode($path);
// 파일 경로 읽기
echo htmlentities(file_get_contents("uploads1/" . $path));
//------------------------------------- 
    - 인코딩 없음 
http://localhost/php/double_enc.php?file=../../.env1 
    - 1번 인코딩 - 서버에 사용될때는 한번 자동으로 디코딩 되므로 인코딩 없음과 입력은 결과적으로 동일
http://localhost/php/double_enc.php?file=..%2F..%2F.env1 
    - 2번 인코딩 - 위 코드의 보안 필터 통과 
http://localhost/php/double_enc.php?file=..%252F..%252F.env1 
//----------------------------------------------------------------------------- 
< 크로스 사이트 스크립팅 공격 (XSS , Cross Site Scripting ) > 
    - 사용자의 자바스크립트 코드를 다른 사용자에게 실행
<?php
// 이미 자동으로 디코딩된 상태(1차 디코딩) , 
// 이중인코딩 입력시 :  %253C  =>  %3C 로 변환되어 들어옴
$name0 = $name = $_GET["name"] ?? '';
// 보안 조치 : 위험 문자 변경,   <   =>   <
// 하지만 < 가 %3C 로 변경되어 있는 상태라서 변경에 적용 안됨
$name = htmlentities($name);
// 사용자 입력 디코딩(코드상으로는 처음이지만, 실제는 2차 디코딩)
// 공격 코드가 완성됨
$name = urldecode($name);
// 출력시 사용자 자바스크립트 코드가 실행됨
echo "Hello " . $name;
//------------------------------------- 
    - 인코딩 없음 
http://localhost/php/double_enc2.php?name=<script>console.log(1)</script> 
    - 1번 인코딩 
http://localhost/php/double_enc2.php?name=%3Cscript%3Econsole.log%281%29%3C%2Fscript%3E 
    - 2번 인코딩 - htmlentities를 통한 스크립트 필터링이 무력화됨 
http://localhost/php/double_enc2.php?name=%253Cscript%253Econsole.log%25281%2529%253C%252Fscript%253E 
//-----------------------------------------------------------------------------
< 방어법 > 
* 두번의 디코딩이 없는지 확인 
    - 디코딩을 코드상에서 한번해도 실제로는 2번한 것이 됨 
        - 사용자 입력이 들어올때 자동으로 1번 디코딩 된 상태 
* 보안 검증전에 디코딩해서 검증 
    - 이후 코드에 사용되는 수준으로 완전히 디코딩된 상태에서 보안검증 코드를 실행한다.
//------------------------------------- 
< 참고 >
https://en.wikipedia.org/wiki/Double_encoding
URL Encoded Attacks
https://www.cgisecurity.com/lib/URLEmbeddedAttacks.html
Double Encoding 
https://owasp.org/www-community/Double_Encoding 
JavaScript 삽입 공격 방지(VB) 
https://learn.microsoft.com/ko-kr/aspnet/mvc/overview/older-versions-1/security/preventing-javascript-injection-attacks-vb 
CWE-174: Double Decoding of the Same Data 
https://cwe.mitre.org/data/definitions/174.html 
  
CWE-180: Incorrect Behavior Order: Validate Before Canonicalize 
https://cwe.mitre.org/data/definitions/180.html