网络安全-XSS跨站脚本攻击

来源:互联网 发布:大数据销售成功案例 编辑:程序博客网 时间:2024/06/07 19:12
1. XSS攻击原理
XSS原称为CSS(Cross-Site Scripting),因为和层叠样式表(Cascading Style Sheets)重名,所以改称为XSS(X一般有未知的含义,还有扩展的含义)。XSS攻击涉及到三方:攻击者,用户,web server。用户是通过浏览器来访问web server上的网页,XSS攻击就是攻击者通过各种办法,在用户访问的网页中插入自己的脚本,让其在用户访问网页时在其浏览器中进行执行。攻击者通过插入的脚本的执行,来获得用户的信息,比如cookie,发送到攻击者自己的网站(跨站了)。所以称为跨站脚本攻击。XSS可以分为反射型XSS和持久性XSS,还有DOM Based XSS。(一句话,XSS就是在用户的浏览器中执行攻击者自己定制的脚本。)
1.1 反射型XSS
反射性XSS,也就是非持久性XSS。用户点击攻击链接,服务器解析后响应,在返回的响应内容中出现攻击者的XSS代码,被浏览器执行。一来一去,XSS攻击脚本被web server反射回来给浏览器执行,所以称为反射型XSS。
特点:
1> XSS攻击代码非持久性,也就是没有保存在web server中,而是出现在URL地址中;
2> 非持久性,那么攻击方式就不同了。一般是攻击者通过邮件,聊天软件等等方式发送攻击URL,然后用户点击来达到攻击的;
1.2 持久型XSS
区别就是XSS恶意代码存储在web server中,这样,每一个访问特定网页的用户,都会被攻击。
特点:
1> XSS攻击代码存储于web server上;
2> 攻击者,一般是通过网站的留言、评论、博客、日志等等功能(所有能够向web server输入内容的地方),将攻击代码存储到web server上的;
有时持久性XSS和反射型XSS是同时使用的,比如先通过对一个攻击url进行编码(来绕过xss filter),然后提交该web server(存储在web server中), 然后用户在浏览页面时,如果点击该url,就会触发一个XSS攻击。当然用户点击该url时,也可能会触发一个CSRF(Cross site request forgery)攻击。
1.3 DOM based XSS
基于DOM的XSS,也就是web server不参与,仅仅涉及到浏览器的XSS。比如根据用户的输入来动态构造一个DOM节点,如果没有对用户的输入进行过滤,那么也就导致XSS攻击的产生。过滤可以考虑采用esapi4js
参见:http://www.freebuf.com/articles/web/29177.html ,http://www.zhihu.com/question/26628342/answer/33504799

2. XSS 存在的原因
XSS 存在的根本原因是,对URL中的参数,对用户输入提交给web server的内容,没有进行充分的过滤。如果我们能够在web程序中,对用户提交的URL中的参数,和提交的所有内容,进行充分的过滤,将所有的不合法的参数和输入内容过滤掉,那么就不会导致“在用户的浏览器中执行攻击者自己定制的脚本”。
但是,其实充分而完全的过滤,实际上是无法实现的。因为攻击者有各种各样的神奇的,你完全想象不到的方式来绕过服务器端的过滤,最典型的就是对URL和参数进行各种的编码,比如escape, encodeURI, encodeURIComponent, 16进制,10进制,8进制,来绕过XSS过滤。那么我们如何来防御XSS呢?

3. XSS 攻击的防御
XSS防御的总体思路是:对输入(和URL参数)进行过滤,对输出进行编码
也就是对提交的所有内容进行过滤,对url中的参数进行过滤,过滤掉会导致脚本执行的相关内容;然后对动态输出到页面的内容进行html编码,使脚本无法在浏览器中执行。虽然对输入过滤可以被绕过,但是也还是会拦截很大一部分的XSS攻击


4、XSS过滤函数总结:
strip_tags( string$str [, string$allowable_tags ] )该函数尝试返回给定的字符串 str 去除空字符、HTML 和 PHP 标记后的结果。
(allowable_tags
使用可选的第二个参数指定不被去除的字符列表。
例如:strip_tags($text'<p><a>');// 允许 <p> 和 <a>
htmlspecialchars把预定义的字符 "<" (小于)和 ">" (大于)转换为 HTML 实体
预定义的字符是:
  • & (和号)成为 &
  • " (双引号)成为 "
  • ' (单引号)成为 '
  • < (小于)成为 <
  • > (大于)成为 >
htmlentities把字符转换为 HTML 实体


5、特殊设置预防
(1)HttpOnly防止劫取Cookie
HttpOnly最早由微软提出,至今已经成为一个标准。浏览器将禁止页面的Javascript访问带有HttpOnly属性的Cookie。目前主流浏览器都支持,HttpOnly解决是XSS后的Cookie支持攻击。


6、过滤函数总结
(1)通用的XSS攻击过滤函数
<?phpfunction RemoveXSS($val) {// remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed// this prevents some character re-spacing such as <java\0script>// note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs$val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','',$val);// straight replacements, the user should never need these since they're normal characters// this prevents like <IMG SRC=@avascript:alert('XSS')>$search ='abcdefghijklmnopqrstuvwxyz';$search .='ABCDEFGHIJKLMNOPQRSTUVWXYZ';$search .='1234567890!@#$%^&*()';$search .='~`";:?+/={}[]-_|\'\\';for ($i =0;$i < strlen($search);$i++) {// ;? matches the ;, which is optional // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars// @ @ search for the hex values$val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i',$search[$i],$val);// with a ; // @ @ 0{0,7} matches '0' zero to seven times$val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/',$search[$i],$val);// with a ; }// now the only remaining whitespace attacks are \t, \n, and \r$ra1 =Array('javascript','vbscript','expression','applet','meta','xml','blink','link','style','script','embed','object','iframe','frame','frameset','ilayer','layer','bgsound','title','base');$ra2 =Array('onabort','onactivate','onafterprint','onafterupdate','onbeforeactivate','onbeforecopy','onbeforecut','onbeforedeactivate','onbeforeeditfocus','onbeforepaste','onbeforeprint','onbeforeunload','onbeforeupdate','onblur','onbounce','oncellchange','onchange','onclick','oncontextmenu','oncontrolselect','oncopy','oncut','ondataavailable','ondatasetchanged','ondatasetcomplete','ondblclick','ondeactivate','ondrag','ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop','onerror','onerrorupdate','onfilterchange','onfinish','onfocus','onfocusin','onfocusout','onhelp','onkeydown','onkeypress','onkeyup','onlayoutcomplete','onload','onlosecapture','onmousedown','onmouseenter','onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup','onmousewheel','onmove','onmoveend','onmovestart','onpaste','onpropertychange','onreadystatechange','onreset','onresize','onresizeend','onresizestart','onrowenter','onrowexit','onrowsdelete','onrowsinserted','onscroll','onselect','onselectionchange','onselectstart','onstart','onstop','onsubmit','onunload');$ra = array_merge($ra1,$ra2);$found =true;// keep replacing as long as the previous round replaced somethingwhile ($found ==true) {$val_before =$val;for ($i =0;$i < sizeof($ra);$i++) {$pattern ='/';for ($j =0;$j < strlen($ra[$i]);$j++) {if ($j >0) {$pattern .='(';$pattern .='(&#[xX]0{0,8}([9ab]);)';$pattern .='|';$pattern .='|(&#0{0,8}([9|10|13]);)';$pattern .=')*'; }$pattern .=$ra[$i][$j]; } $pattern .='/i';$replacement = substr($ra[$i],0,2).'<x>'.substr($ra[$i],2);// add in <> to nerf the tag $val = preg_replace($pattern,$replacement,$val);// filter out the hex tags if ($val_before ==$val) {// no replacements were made, so exit the loop$found =false; } } }return$val; }

(2)Discuz系统中 防止XSS漏洞攻击,过滤HTML危险标签属性的PHP函数
function string_remove_xss($html) {
    preg_match_all("/\<([^\<]+)\>/is"$html$ms);
 
    $searchs[] = '<';
    $replaces[] = '&lt;';
    $searchs[] = '>';
    $replaces[] = '&gt;';
 
    if ($ms[1]) {
        $allowtags = 'img|a|font|div|table|tbody|caption|tr|td|th|br|p|b|strong|i|u|em|span|ol|ul|li|blockquote';
        $ms[1] = array_unique($ms[1]);
        foreach ($ms[1] as $value) {
            $searchs[] = "&lt;".$value."&gt;";
 
            $value = str_replace('&amp;''_uch_tmp_str_'$value);
            $value = string_htmlspecialchars($value);
            $value = str_replace('_uch_tmp_str_''&amp;'$value);
 
            $value = str_replace(array('\\''/*'), array('.''/.'), $value);
            $skipkeys = array('onabort','onactivate','onafterprint','onafterupdate','onbeforeactivate','onbeforecopy','onbeforecut','onbeforedeactivate',
                    'onbeforeeditfocus','onbeforepaste','onbeforeprint','onbeforeunload','onbeforeupdate','onblur','onbounce','oncellchange','onchange',
                    'onclick','oncontextmenu','oncontrolselect','oncopy','oncut','ondataavailable','ondatasetchanged','ondatasetcomplete','ondblclick',
                    'ondeactivate','ondrag','ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop','onerror','onerrorupdate',
                    'onfilterchange','onfinish','onfocus','onfocusin','onfocusout','onhelp','onkeydown','onkeypress','onkeyup','onlayoutcomplete',
                    'onload','onlosecapture','onmousedown','onmouseenter','onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup','onmousewheel',
                    'onmove','onmoveend','onmovestart','onpaste','onpropertychange','onreadystatechange','onreset','onresize','onresizeend','onresizestart',
                    'onrowenter','onrowexit','onrowsdelete','onrowsinserted','onscroll','onselect','onselectionchange','onselectstart','onstart','onstop',
                    'onsubmit','onunload','javascript','script','eval','behaviour','expression','style','class');
            $skipstr = implode('|'$skipkeys);
            $value = preg_replace(array("/($skipstr)/i"), '.'$value);
            if (!preg_match("/^[\/|\s]?($allowtags)(\s+|$)/is"$value)) {
                $value = '';
            }
            $replaces[] = empty($value) ? '' : "<" . str_replace('&quot;''"'$value) . ">";
        }
    }
    $html = str_replace($searchs$replaces$html);
 
    return $html;
}
 
function string_htmlspecialchars($string$flags = null) {
    if (is_array($string)) {
        foreach ($string as $key => $val) {
            $string[$key] = string_htmlspecialchars($val$flags);
        }
    else {
        if ($flags === null) {
            $string = str_replace(array('&''"''<''>'), array('&amp;''&quot;''&lt;''&gt;'), $string);
            if (strpos($string'&amp;#') !== false) {
                $string = preg_replace('/&amp;((#(\d{3,5}|x[a-fA-F0-9]{4}));)/''&\\1'$string);
            }
        else {
            if (PHP_VERSION < '5.4.0') {
                $string = htmlspecialchars($string$flags);
            else {
                if (!defined('CHARSET') || (strtolower(CHARSET) == 'utf-8')) {
                    $charset = 'UTF-8';
                else {
                    $charset = 'ISO-8859-1';
                }
                $string = htmlspecialchars($string$flags$charset);
            }
        }
    }
 
    return $string;
}