我有一个安全函数,它是脚本的一部分。它应该过滤掉在输入表单中执行的恶意代码。它对 A-Z 中的普通字符没有问题,但它拒绝带有 á、ñ、ö 等字符的输入。
我该怎么做才能不拒绝包含这些字符的表单输入?这是函数:
function add_special_chars($string, $no_quotes = FALSE)
{
$patterns = array(
"/(?i)javascript:.+>/",
"/(?i)vbscript:.+>/",
"/(?i)<img.+onload.+>/",
"/(?i)<body.+onload.+>/",
"/(?i)<layer.+src.+>/",
"/(?i)<meta.+>/",
"/(?i)<style.+import.+>/",
"/(?i)<style.+url.+>/"
);
$string = str_ireplace("&","&",$string);
if (!$no_quotes) $string = str_ireplace("'","'",$string);
$string = str_ireplace('"','"',$string);
$string = str_ireplace('<','<',$string);
$string = str_ireplace('>','>',$string);
$string = str_ireplace(' ',' ',$string);
foreach ($patterns as $pattern)
{
if(preg_match($pattern, $string))
{
$string = strip_tags($string);
}
}
$string = preg_replace('#(&'#*'w+)['x00-'x20]+;#u', "$1;", $string);
$string = preg_replace('#(&'#x*)([0-9A-F]+);*#iu', "$1$2;", $string);
$string = html_entity_decode($string, ENT_COMPAT, LANG_CODEPAGE);
$string = preg_replace('#(<[^>]+['x00-'x20'"'''/])(on|xmlns)[^>]*>#iUu', "$1>", $string);
$string = preg_replace('#([a-z]*)['x00-'x20'/]*=['x00-'x20'/]*(['`'''"]*)['x00-'x20'/]*j['x00-'x20]*a['x00-'x20]*v['x00-'x20]*a['x00-'x20]*s['x00-'x20]*c['x00-'x20]*r['x00-'x20]*i['x00-'x20]*p['x00-'x20]*t['x00-'x20]*:#iUu', '$1=$2nojavascript...', $string);
$string = preg_replace('#([a-z]*)['x00-'x20'/]*=['x00-'x20'/]*(['`'''"]*)['x00-'x20'/]*v['x00-'x20]*b['x00-'x20]*s['x00-'x20]*c['x00-'x20]*r['x00-'x20]*i['x00-'x20]*p['x00-'x20]*t['x00-'x20]*:#iUu', '$1=$2novbscript...', $string);
$string = preg_replace('#([a-z]*)['x00-'x20'/]*=['x00-'x20'/]*(['`'''"]*)['x00-'x20'/]*-moz-binding['x00-'x20]*:#Uu', '$1=$2nomozbinding...', $string);
$string = preg_replace('#([a-z]*)['x00-'x20'/]*=['x00-'x20'/]*(['`'''"]*)['x00-'x20'/]*data['x00-'x20]*:#Uu', '$1=$2nodata...', $string);
$string = preg_replace('#(<[^>]+['x00-'x20'"'''/])style[^>]*>#iUu', "$1>", $string);
$string = preg_replace('#</*'w+:'w[^>]*>#i', "", $string);
do
{
$original_string = $string;
$string = preg_replace('#</*(applet|meta|xml|blink|link|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $string);
}
while ($original_string != $string);
return $string;
}
更新:我发现以下行似乎导致了问题,但不确定原因:
$string = preg_replace('#(<[^>]+['x00-'x20'"'''/])style[^>]*>#iUu', "$1>", $string);
这是一个坏主意。 不过,函数中最糟糕的部分是htmlentity_decode()
的一半,这完全破坏了该函数的前 1/2。 攻击者只需对引号和括号进行编码,您只需为攻击者构建有效负载。 strip_tags()
是一个笑话,不是防止XSS的好方法。 这个函数的主要问题是它太简单了。 HTMLPurifer由数千个正则表达式组成,它做得更好,但它并不完美。
你几乎无法解决最常见的XSS形式。 XSS是一个输出问题,你不能指望通过一些神奇的函数传递所有输入并假设它是安全的。 XSS 取决于它的使用方式。
在没有实际运行您的代码的情况下,我认为这样的事情会绕过它:
<a href='javA%3bS%3bcript:%3balert(1)'>so very broken</a>
甚至更简单:
<img src=x onerror=alert(1) />
就像我说的,这是一个极其复杂的问题的严重过度简化。