1

我有一个安全功能,它是脚本的一部分。它应该过滤掉在输入表单中执行的恶意代码。它可以正常处理来自 AZ 的普通字符,但它会拒绝带有 á、ñ、ö 等字符的输入。

我该怎么做才能不拒绝带有这些字符的表单输入?这是功能:

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("&amp;","&",$string);

    if (!$no_quotes) $string = str_ireplace("&#039;","'",$string);

    $string = str_ireplace('&quot;','"',$string);
    $string = str_ireplace('&lt;','<',$string);
    $string = str_ireplace('&gt;','>',$string);
    $string = str_ireplace('&nbsp;',' ',$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);
4

1 回答 1

4

这是一个坏主意。你的函数最糟糕的部分是htmlentity_decode()一半,它完全破坏了这个函数的前 1/2。攻击者只需对引号和括号进行编码,您只需为攻击者构建有效载荷。 strip_tags()是个玩笑,并不是防范 XSS 的好方法。这个函数的主要问题是它太简单了。 HTMLPurifer数千个正则表达式组成,它做得更好,但并不完美。

您几乎没有解决最常见的 XSS 形式。 XSS 是一个输出问题,你不能指望通过一些神奇的功能传递所有输入并假设它是安全的。XSS 取决于它的使用方式

在没有实际运行您的代码的情况下,我认为这样的事情会绕过它:

<a href='jav&#x41%3b&#x53%3bcript&#x3a%3balert(1)'>so very broken</a>

或者甚至更简单的东西:

<img src=x onerror=alert(1) />

就像我说的那样,这是对一个极其复杂的问题的严重过度简化

于 2012-06-23T00:13:04.753 回答