在PHP中防止跨站点脚本

时间:2010-06-30 09:13:41

标签: php security

我不确定这是正确的方法,但我将此功能用于输入。例如联系表格:

RemoveXSS(mysql_real_escape_string($_POST['input']))

但是通过扫描,有这样的结果:

Parameter Name: Query Based 
Parameter Type: FullQueryString 
Attack Pattern: /"ns="alert(0x00058B) 

点击上面的网址时,我无法看到页面中的任何内容。但是我的代码却出了什么问题。

///////////

function RemoveXSS($val)
{

$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=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A &#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
$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

    // &#x0040 @ search for the hex values
    $val = preg_replace('/(&#[xX]0{0,8}' . dechex(ord($search[$i])) . ';?)/i', $search[$i],
        $val); // with a ;
    // &#00064 @ 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 something
while ($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;
}

提前致谢

3 个答案:

答案 0 :(得分:8)

这对我来说似乎有点大不了解。 htmlspecialchars($val)filter_var($val, FILTER_SANITIZE_STRING);

之类的内容有什么问题

答案 1 :(得分:3)

您正在混合来自XSS(注入浏览器)和SQL注入的保护。

mysql_real_escape_string用于转义要在SQL查询中使用的字符串,例如,避免注入“SELECT * FROM foo WHERE name =”。$ name

“坏”字符串的一个示例是将要执行的SQL命令。

对于浏览器输出,htmlentities()或htmlspecialchars()可用于转义从易受XSS攻击而输出的字符串。

“坏”字符串的一个示例是:注册了包含HTML标记的名称的用户。如果输出此用户的名称而不进行转义,则会注入HTML标记。

没有理由手动过滤每个可能的JavaScript属性或标记 - 无论如何你可能会错过一些。 htmlentities()/ htmlspecialchars()会转发像

这样的东西
<script language="JavaScript">

&lt;script language="JavaScript"&gt;

所以代码只会被浏览器安全地显示而不是被执行。

摘要是:有两种类型的转义,一种用于SQL,一种用于HTML。混合它们是没有意义的。

答案 2 :(得分:2)

混合sql注入和xss过滤器是一个坏主意。它们是非常不同的攻击,它们使用非常不同的控制字符。

如果您只想停止XSS,请使用htmlspeiclchars($var,ENT_QUOTES);。如果您只想允许安全的html,请使用HTML Purifier

如果要停止sql注入,请使用PDO参数化查询。