常见的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("'","&apos;",$_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*/ 等属性内,则必须出现在属性值的开头才能触发。

 

posted @ 2025-07-11 14:55  小碗吃不胖的  阅读(63)  评论(0)    收藏  举报