Web 프로그램/테이블, 게시판, 검색

XSS(cross-site scripting) filtering function in PHP

Link2Me 2018. 5. 1. 10:14

네이버스마트 에디터를 이용하여 게시판을 만들어보려고 하니 XSS 대한 공부를 해야 할 거 같다.


크로스 사이트 스크립트란
사이트 간 스크립팅(또는 크로스 사이트 스크립팅, 영문 명칭 cross-site scripting, 영문 약어 XSS)은 웹 애플리케이션에서 많이 나타나는 취약점의 하나로 웹 페이지에 악성 스크립트를 삽입할 수 있는 취약점이다.
주로 여러 사용자가 보게 되는 게시판에 악성 스크립트가 담긴 글을 올리는 형태로 이루어진다.
이 취약점은 웹 애플리케이션이 사용자로부터 입력 받은 값을 제대로 검사하지 않고 사용할 경우 나타난다.
이 취약점으로 해커가 사용자의 정보(쿠키, 세션 등)를 탈취하거나, 자동으로 비정상적인 기능을 수행할 수 있다.
주로 다른 웹사이트와 정보를 교환하는 식으로 작동하므로 사이트 간 스크립팅이라고 한다.



기능을 테스트한 걸 적어둔다. 아직 완벽하게 다 기능 구현을 이해 못한거 같다.

구글링해서 찾은 코드와 여러 자료를 참조하여 함수를 만들어보고 있는 중이다.


입력 데이터


MySQL DB에 저장된 내용(html_encode 함수 이용)




 <?php
class bbsClass {

    function html_encode($str){
        // SQL 과 XSS 공격을 모두 막는 함수
        // htmlentities는 문자열에서 모든 HTML을 제거한다. 한글이 깨질수 있다.
        // ENT_QUOTES : 홑따옴표와 겹따옴표 모두 변환
        // htmlspecialchars, htmlentities 두개다 기본 euc-kr을 지원하지 않는다.
        return htmlentities($this->mysql_fix_string($str), ENT_QUOTES, "UTF-8");
    }

    function mysql_fix_string($str){
        global $db;
        // escape variables for security
        // mysqli_real_escape_string() 함수는 SQL 문에서 특수 문자열을 이스케이프한다.
        // $firstname = mysqli_real_escape_string($con, $_POST['firstname']);
        if(get_magic_quotes_gpc()) $str = stripslashes($str);
        return mysqli_real_escape_string($db,$str);
    }

    function html_decode($str){
        return htmlspecialchars_decode(stripslashes($str));
    }

    function xss_clean($data){ // html_decode 함수의 일종
        // 출처 : https://stackoverflow.com/questions/1336776/xss-filtering-function-in-php
        // Fix &entity\n;
        $data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
        $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
        $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
        $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

        // Remove any attribute starting with "on" or xmlns
        $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

        // Remove javascript: and vbscript: protocols
        $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
        $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
        $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

        // Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
        $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
        $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
        $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

        // Remove namespaced elements (we do not need them)
        $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

        do
        {
            // Remove really unwanted tags
            $old_data = $data;
            $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
        }
        while ($old_data !== $data);

        // we are done...
        return $data;
    }

}//end class bbsClass


검색하다보니 HTML Purifier 를 이용한 필터링을 하는 걸 추천하는거 같다.

http://htmlpurifier.org/ 에서 파일을 다운로드하여 압축을 푼다.

HTML Purifier 4.10.0 버전이 PHP5, PHP7 지원한다고 적혀있다.


기능을 테스트 해보니 $html_decode 함수인거 같다.

https://gist.github.com/kijin/5829736 에 사용법이 잘 설명되어 있다.


728x90