[Tips]Do not Echo into Javascript
by jno[jno_0x71@yahoo.com.cn]
date: 2007-05-25
http://www.ph4nt0m.org
<?php
function htmlencode($str)
{
$str = htmlspecialchars($str);
$str = preg_replace("/\'/i", "'", $str);
return $str;
}
$str = htmlencode($_GET['str']);
?>
<div style="width: 200px; height: 200px; background-color: #ccc;"
onmouseover="javascript: alert('<?php echo $str;?>')" />
function htmlencode($str)
{
$str = htmlspecialchars($str);
$str = preg_replace("/\'/i", "'", $str);
return $str;
}
$str = htmlencode($_GET['str']);
?>
<div style="width: 200px; height: 200px; background-color: #ccc;"
onmouseover="javascript: alert('<?php echo $str;?>')" />
如果你习惯用上面的方式写代码,把用户输入输出到客户端作为javascript的一部分,那么就有问题了,即使你有编码用户输入的习惯也无济于事,因为用户输入可以使用引号来闭合javascript的字符串变量,然后加入他自己的恶意代码:
http://localhost/vul_code.php?str=aaa');alert('bbb
你这时可能还有点疑问,我htmlencode了,单双引号也被转义成"和'了,怎么还可能突破呢?事实上htmlencode了的内容作为html元素的属性里的脚本时,是被按照它的原意来执行的,你可以试试这个例子就明白了:
<input type="button" value="双引号"
onclick="javascript: alert("双引号& quot;);" />
<input type="button" value="单引号"
onclick="javascript: alert('单引号');" />
onclick="javascript: alert("双引号& quot;);" />
<input type="button" value="单引号"
onclick="javascript: alert('单引号');" />
那么,怎么样解决这样的问题,一个办法就是再对字符串进行javascript转义,把单双引号分别转义成\"和\',避免利用这两个符号突破,但是要转义全了还是需要做点文章,因为单双引号的变形形式还是很多样的,比如:
双引号:" &#34; &#x22; &#0034; &#000034; &#00000034; ...
单引号:' ' ' ' ...
难免会有疏漏,所以这样做不太好,如果有疏漏过滤就会被突破。另外有一种思路来解决这个问题就是避免这样的写法,为什么非要从服务器端输出到javascript里呢,我们很容易可以用其他办法实现相同的效果,又更加安全:
<?php
function htmlencode($str)
{
$str = htmlspecialchars($str);
$str = preg_replace("/\'/i", "'", $str);
return $str;
}
$str = htmlencode($_GET['str']);
?>
<div style="width: 200px; height: 200px; background-color: #ccc;"
onmouseover="javascript: alert(this.getAttribute('server_data'))"
server_data="<?php echo $str;?>"/>
function htmlencode($str)
{
$str = htmlspecialchars($str);
$str = preg_replace("/\'/i", "'", $str);
return $str;
}
$str = htmlencode($_GET['str']);
?>
<div style="width: 200px; height: 200px; background-color: #ccc;"
onmouseover="javascript: alert(this.getAttribute('server_data'))"
server_data="<?php echo $str;?>"/>
把数据输出到一个属性里,这里的server_data就是我们开辟的一个服务器数据岛,因为是输出到普通的属性里面,所以htmlencode就可以保证它没法突破这个双引号,那么这个数据岛就是安全的,脚本需要数据的话,就通过dom的方式从安全的服务器数据岛取得数据。
所以,说了这么多,就是表达一个意思,避免输出到javascript里面,当然其他script也不行。
没有评论:
发表评论