1. 디코딩 전 필터링
일반적으로는 웹에서 클라이언트로부터 전달받은 값을 디코딩하여 사용자의 입력값을 검증하지만, 만약 디코딩하기 전에
검증을 수행하면 공격자가 더블 인코딩된 값을 전송하여 검증을 우회할 수 있게 됩니다.
2. 더블 인코딩
말 그대로 전송하는 값을 두번 인코딩하는 것입니다. 예를 들어 설명해보겠습니다.
<script>alert('hello');</script>
이 코드의 일부를 한번 인코딩한 값은 다음과 같습니다.
%3Cscript%3Ealert%28%27hello%27%29%3C/script%3E
<, ', (,) 기호를 인코딩했습니다. %xx 형식으로 되어있으며 xx에는 해당 기호의 ascii 코드 16진수 값이 들어갑니다.
예시) ( == %28 (28 : ( 의 ascii 코드 16진수 값)
그리고 이제 한번 더 인코딩해서 더블 인코딩을 해보겠습니다.
%253Cscript%253Ealert%2528%2527hello%2527%2529%253C/script%253E
달라진 점은 기존의 인코딩한 값에 25가 붙어있는 것입니다. 이렇게 변한 이유는 % 기호를 인코딩하면 %25 가 되기
때문입니다. %253C 가 디코딩 되면 %3C 가 되고, 한번 더 디코딩 되면 < 가 됩니다.
3. 실습
실습을 위해 간단한 코드를 작성했습니다.
<?php
$sa = $_GET['test'];
if(strpos($sa,'<script>' !== false) {
die('no script');
}
$sa_decode = urldecode($_GET['test']);
?>
<h1>result : <?php echo $sa_decode; ?></h1>
GET 메소드로 값을 전달받은 값에 <script> 가 포함되어있으면 no script 를 출력하고 종료되는 코드이며 if 문을 지나면
전달받은 값을 $sa_decode 변수에 디코딩하여 저장하고 결괏값을 출력합니다.
<script> 를 전송했을 때 no script 가 출력됩니다.
%3Cscript%3Ealert%28%27hello%27%29%3C/script%3E 값을 전송했습니다. 전송한 값은 한번 디코딩되어 검증에
걸리게 됩니다. 이제 더블인코딩 된 값을 전송해보겠습니다.
%253Cscript%253Ealert%2528%2527hello%2527%2529%253C/script%253E 값을 전송했습니다.
더블 인코딩 된 값은 전송되면서 한번 디코딩되었지만 두번 인코딩 되어있었기 때문에 검증 과정을 우회할 수
있었습니다. 이후 한번더 디코딩 되면서 스크립트가 실행되어 출력된 것입니다.