常见的XSS缺陷代码和修复方案
1、什么都没过滤,直接输出到html
<?php if (! isset($_GET['name'])) { header('Location: index.php?name=world'); exit(); } $name = $_GET['name']; echo "Hello $name"; ?>
利用场景:firefox http://localhost/test/reflection_xss/xss_simple_html.php?name=%3cscript%3Ealert(11)%3C/script%3E
修复方案:在html标签中输出(使用htmlEncode)
2、过滤script、alert关键字
<?php if (! isset($_GET['name'])) { header('Location: index.php?name=world'); exit(); } $name = $_GET["name"]; if (preg_match('/script|alert/i', $name)) { die("no script enable!"); } echo $name; ?>
利用场景:firefox http://localhost/test/reflection_xss/xss_remove_script.php?name=%3Cimg%20src=0%20onerror=prompt(1)%3E
修复方案:在html标签中输出(使用htmlEncode)
3、输出到js,默认只编码双引号
<?php if (! isset($_GET['name'])) { header('Location: index.php?name=world'); exit(); } $name= $_GET["name"]; ?> <script> var a= '<?php echo htmlentities($name); ?>'; </script>
利用场景:firefox http://localhost/test/reflection_xss/xss_script_singlequote.php?name=aa%27;alert(11);//
修复方案:在script标签中输出(使用javascriptEncode)
4、输出到 js,未做任何过滤
<?php if (! isset($_GET['name'])) { header('Location: index.php?name=world'); exit(); } $name = $_GET["name"]; ?> <script> var $a= "<?php echo $name; ?>"; </script>
利用场景:firefox http://localhost/test/reflection_xss/xss_script_doublequote.php?name=aa%22;alert(1);//
场景:
var s1mba="http://ke.qq.com/cgi-bin/courseDetail?course_id=109431"+alert(903606738); var pg_CartoonDetail = new BIU.Page({ name: 'pg_CartoonDetail', ..., current: '123'-alert(1)-'', ...});
修复方案:在script标签中输出(使用javascriptEncode)
5、输出到js,\` 转义,返回charset 是 gbk
<?php $var = str_replace('"', '\\"', $_GET['var']); # addslashes ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <script> var b = "<?php echo $var;?>"; </script> </head> </html>
利用场景: firefox 页面编码设置为gbk http://localhost/test/reflection_xss/xss_script_gbk.php?var=aa%ae%22;alert(11);//`
修复方案:在script标签中输出(使用javascriptEncode),但此处不要用`` 转义的方式,可以用unicode等方式
6、jsoncallback 接口,返回没有过滤,且content-type 为 text/html
<?php if (isset($_GET['q'])) { $q = $_GET['q']; $arr = array( 'a'=>'b', 'c'=>'d', ); echo $q."({".json_encode($arr)."})"; }else{ header("location:?q=test"); } ?>
利用场景: firefox http://localhost/test/reflection_xss/xss_in_jsoncallback.php?q=%3Cscript%3Ealert(11)%3C/script%3E
修复方案:对于传入的callback参数,使用 htmlspecialchars 编码,或者把返回content-type 定为 application/json,同时添加X-Content-Type-Options: nosniff头。
注意:添加X-Content-Type-Options: nosniff头前,请确认站点下所有接口已设置了与内容相符的Content-type。
7、jsoncallback 接口,返回没有作任何限制,且content-type为application/javascript或者application/x-javascript
利用场景:在某些场景下,IE会忽略application/javascript或者application/x-javascript的content-type设置,因此将触发反射型XSS。此外,当页面Content-type设置为application/javascript或者application/x-javascript时,还可以 被攻击者绕过已部署的CSP防护策略,案例请参见:
http://www.freebuf.com/news/139672.html
修复方案:对于传入的callback参数,做长度限制,且只允许callback中出现字母、数字和下划线。同时,把服务器的HTTP响应数据包的content-type 定为 application/json或 text/javascript,同时添加X-Content-Type-Options: nosniff头。
注意:添加X-Content-Type-Options: nosniff头前,请确认站点下所有接口已设置了与内容相符的Content-type。
8、输出到标签属性,没有过滤单引号(双引号,没有引号同理)
<?php if (isset($_GET['q'])) { $q = $_GET['q']; $q = preg_replace('/[\<\>]/i', '', $q); echo "<input type='text' value='".$q."'>"; }else{ header("location:?q=test"); } ?>
利用场景:firefox http://localhost/test/reflection_xss/xss_in_htmlattr_singlequote.php?q=aa%27%20onmouseover=prompt(111)%20bad=%27
修复方案: 这里过滤了< >,但我们还是可以闭合属性引号进而重设一个属性,故需要 htmlspecialchars 编码下
9、输出到html 事件中,有多种过滤情形
<?php if (! isset($_GET['a'])) { header('Location: index.php?a=world'); exit(); } ?> <html> <?php $a = htmlspecialchars($_GET['a'], ENT_QUOTES); $b = str_replace("'","\\x27",$_GET['b']); $b = str_replace('"','\\x22',$b); //$b = str_replace("'","'",$_GET['b']); $c = htmlspecialchars($_GET['c']); $d = htmlspecialchars($_GET['d'], ENT_QUOTES); //$e = htmlspecialchars($_GET['e']); ?> <body> <input id="a" type="text" value="please input" onfocus="if(value == 'please input'){value='<?php echo $a;?>'}"/> <input id="b" type="text" value="please input" onfocus="if(value == 'please input'){value='<?php echo $b;?>'}"/> <input id="c" type="text" value="please input" onfocus="if(value == 'please input'){value='<?php echo $c;?>'}"/> <input id="d" type="text" value="please input" onfocus="if(value == 'please input'){var a=<?php echo $d;?>;value=a;}"/> <!-- <input id="e" type="text" value="please input" onfocus='if(value == "please input"){value="<?php echo $e;?>"}'/> --> </body> </html>
利用场景:firefox
http://localhost/test/reflection_xss/xss_in_html_event.php?a=%27;alert(11);}//
http://localhost/test/reflection_xss/xss_in_html_event.php?a=aaa&b=%26%2339;;alert(11);}//
http://localhost/test/reflection_xss/xss_in_html_event.php?a=aaa&b=bbb&c=%27;alert(111);}//
http://localhost/test/reflection_xss/xss_in_html_event.php?a=aaa&b=bbb&c=ccc&d=123;%0D%0Aalert()
修复方案:参数出现的地方浏览器会先进行 htmldecode,再进行jsdecode。如前所述,这里进行jsencode 即可,但不能用\`转义的方式,可以是 unicode 或者 \xXX 方式, 假设用户输入 ',则编码为 \u0027,不会触发;假设用户输入 ',则编码为\u0026\u0023\u0033\u0039\u003b`,不会触发
10、urldecode, htmldecode, base64decode
<?php if (! isset($_GET['end'])) { exit(); } ?> <?php $start = urldecode($_GET['start']); $end = htmlspecialchars_decode($_GET['end']); #$end = $_GET['end']; $b4 = htmlspecialchars($_GET['b4'], ENT_QUOTES); ?> <html><head> <!-- <meta http-equiv="Content-Type" content="text/html; charset=GBK"> --> </head> <body> <p>aaaaaaa</p> <?php echo "ccccc".$start; ?> <?php echo "bbbbb".$end; ?> <?php echo base64_decode($b4); ?> </body> </html>
利用场景:firefox
http://localhost/test/reflection_xss/xss_htmlurlb4_decode.php?start=%253Cscript%253Ealert%252811%2529%253C%252fscript%253E&end=abds&b4
http://localhost/test/reflection_xss/xss_htmlurlb4_decode.php?start=aa&end=%26lt%3Bscript%26gt%3Balert%2811%29%26lt%3B%2fscript%26gt%3B&b4
http://localhost/test/reflection_xss/xss_htmlurlb4_decode.php?start=aa&end=bb&b4=PHNjcmlwdD5hbGVydCgnYWN1bmV0aXgteHNzLXRlc3QnKTwvc2NyaXB0Pgo=
修复方案:这个例子是跟具体业务比较相关的,比如无论是哪种 decode 操作后,经过中间流程的操作,输出到页面时都需要进行 htmlencode
11、输出在标签的href 属性中
<?php if (! isset($_GET['name'])) { header('Location: index.php?name='); exit(); } $name = $_GET["name"]; ?> <a href="<?php echo htmlspecialchars($name,ENT_QUOTES) ?>">button</a>
利用场景: firefox http://localhost/test/reflection_xss/xss_in_htmlattr_href_1.php?name=javascript:alert(1)
修复方案:一般来说,如果变量是完整的url,应该先检查下是否以^http开头,且目的域名是允许的域名列表内,以保证不会出现伪协议类的XSS攻击。接着使用 htmlspecialchars 编码下;或者因为此处是地址栏,可以用 urlencode 编码变量。这里的payload 变形可以有很多,故检查的正则需要很严格,payload 列举如下,如果以下 payload 出现在 src/href/on*/ 等属性内,则必须出现在属性值的开头才能触发。

浙公网安备 33010602011771号