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 に答える