본문 바로가기

PHP

htmlspecialchars로 XSS 공격 방어하기

앞으로 티스토리 대신 blog.stackframe.dev에서 블로깅을 합니다. 이 블로그는 남겨 둘 예정입니다.

XSS 공격은 어떤 면에서는 간단히 막을 수 있을 것처럼 보이지만 다르게 보면 상당히 골치아픈 공격 중 하나입니다. XSS 공격을 막는 것은 아주 간단합니다. 사용자의 입력값에서 html 관련 문자 (< > " ' &)들을 모두 html entity(&lt; &gt; &quot; &apos; &amp;)로 변환시키는 겁니다. 이렇게되면 사용자의 어떠한 입력값도 HTML 요소로 브라우저가 해석하지 않으니 당연히 XSS가 불가능합니다.


PHP에서는 이를 간편하게 할 수 있는 htmlspecialchars라는 함수가 존재합니다. php 메뉴얼

인자로 총 1~4개를 받습니다.

htmlspecialchars(변환할 문자열[, 옵션[, 인코딩[, 더블 인코드]]])

첫 번째 인자로 변환시킬 문자열을 입력합니다.

두 번째 인자로는 옵션을 입력하는데 bit or를 사용하여 여러 옵션들을 조합할 수 있습니다. 옵션에는 현재 PHP 7.1 기준으로 10개가 있지만 중요한 4개만 소개하겠습니다.


ENT_HTML5

HTML5를 기준으로 HTML entity로 변환할 문자들을 결정합니다.


ENT_QUOTES

큰 따옴표(")에 더불어 작은 따옴표(')까지 HTML entity로 변환합니다. HTML 문서를 만들 때 옵션으로 작은 따옴표를 쓰는 경우도 있으니 이 설정을 켜주는 것이 좋습니다.


ENT_SUBSTITUTE

잘못된 코드 유닛 시퀀스(잘못된 UTF-8 포맷)이 발견되면 � 로 치환합니다. 치환하지 않고 없애버리는 ENT_IGNORE 옵션도 있지만 보안의 위험성이 있기 때문에 권장하지 않습니다.


ENT_DISALLOWED

문서 내부에서 나타날 수 없는 문자가 발견되면 � 로 치환합니다. HTML5에서 나타날 수 없는 문자가 있는지는 모르겠지만 일단 설정하는게 좋을 것 같습니다.


위의 옵션들을 사용하려면 ENT_HTML5 | ENT_QUOTES | ENT_SUBSTITUTE | ENT_DISALLOWED 로 작성하시면 됩니다.


세 번째 인자는 인코딩인데 인자를 주지 않으면 php.ini에 설정된 기본 인코딩 형식이 사용됩니다. 요즘 모두 EUC_KR로 사이트를 구축하는 경우는 없을테니 php.ini에 UTF-8로 설정해두고 이 인자를 넣지 않으면 됩니다.


네 번째 인자는 더블 인코딩을 할 지 말지(Boolean) 입니다. 기본 설정은 더블 인코딩을 하는 것입니다. 사용자가 &amp;라는 문자열을 입력했을 때 더블 인코딩을 한다면&amp;amp;라는 문자열로 변환되고, 더블 인코딩을 하지 않는다면 &amp;그대로 출력됩니다.


세 번째와 네 번째의 인자는 기본 설정에서 손 댈 이유가 거의 없기 때문에 두 번째 인자까지만 사용하는 경우가 대부분입니다.


예제로 아래와 같은 스크립트를 만들어 보았습니다.

<?php
    $test = '<img src="#" onerror="alert(1)">';
    echo htmlspecialchars($test, ENT_HTML5 | ENT_QUOTES | ENT_SUBSTITUTE | ENT_DISALLOWED);
?>

실행 결과로 < > " 문자가 모두 HTML entity로 변환된 것을 볼 수 있습니다.

&lt;img src=&quot;#&quot; onerror=&quot;alert(1)&quot;&gt;

이 문자들을 브라우저가 출력하면 <img src="#" onerror="alert(1)"> 그대로 표시됩니다.




다만 현실적으로 보면 저 방법을 사용하기는 여러모로 곤란할 수 있습니다. 특히 게시판 형태의 웹 사이트라면 많은 사이트들이 네이버의 Smart Editor를 적용하는 것을 볼 수 있습니다. 이러한 에디터는 브라우저 상에서 HTML 코드를 생성하여 글을 꾸미고 서버에 등록하는 형태입니다. 이 경우에 무작정 html 관련 문자들을 변환시켜버리면 하나도 포매팅되지 않고 오히려 HTML 코드들이 화면에 표시되는 불상사가 발생합니다. 그러므로 이러한 에디터를 사용하여 글을 등록하는 경우라면 서버 내부에서 XSS를 막는 코드를 추가적으로 도입해야 합니다.

'PHP' 카테고리의 다른 글

[PHP] PDO로 쿼리하기  (0) 2019.04.29
[PHP] PDO로 데이터베이스 접속하기  (0) 2019.04.29