【问题标题】:XSS filtering function in PHPPHP中的XSS过滤功能
【发布时间】:2010-11-23 03:12:45
【问题描述】:

有没有人知道从表单中过滤通用输入的好功能? Zend_Filter_input 似乎需要对输入内容的先验知识,我担心使用 HTML Purifier 之类的东西会对性能产生很大影响。

类似的东西呢:http://snipplr.com/view/1848/php--sacar-xss/

非常感谢您的任何意见。

【问题讨论】:

  • HTMLPUrifier 可能会占用一些资源,但您可能没有发布那么多内容? (例如,与所咨询的相比);;如果您在将数据保存到数据库时运行 HTMLPurifier,而不是在从数据库读取数据时运行,则可能没问题...

标签: php filter xss


【解决方案1】:

简单的方法?使用strip_tags():

$str = strip_tags($input);

您也可以为此使用filter_var()

$str = filter_var($input, FILTER_SANITIZE_STRING);

filter_var() 的优点是您可以通过例如剥离或编码低位和高位字符来控制行为。

这是sanitizing filters的列表。

【讨论】:

  • 那么这是最好的方法还是 HTML Purifier 是获得最大安全性的最佳方法。
  • 虽然 cletus 通常很容易被发现,但使用普通的旧 strip_tags() 是一个巨大的疏忽和安全问题。详情请阅读以下htmlpurifier.org/comparison#striptags
  • strip_tags 的问题在于它不验证属性。所以只要你不允许任何标签,它就应该作为一个 XSS 过滤器。
  • 这不能防止像" onclick="alert('Why it is not blocked?')这样的东西
  • 除非你想剥离每个标签,否则这不是一个安全的 XSS 过滤器。 HTML Purifier(和类似的)库是允许标签和合理安全用户提供的数据的唯一有效方法。
【解决方案2】:

黑客使用多种方式进行 XSS 攻击,PHP 的内置函数无法响应各种 XSS 攻击。因此,strip_tags、filter_var、mysql_real_escape_string、htmlentities、htmlspecialchars 等函数并不能 100% 保护我们。你需要一个更好的机制,下面是解决方案:

function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&','<','>'), array('&','<','>'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

// Remove javascript: and vbscript: protocols
$data = 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]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\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]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

do
{
    // Remove really unwanted tags
    $old_data = $data;
    $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);

// we are done...
return $data;
}

【讨论】:

  • 嘿@Sarfraz 你的函数真的安全吗?
  • 你还应该在前面加上 urldecode 这个脚本在 %22%3E%3Cscript%3Ealert('try_xss');%3C/ 上不起作用脚本%3E
  • Christian Stocker 提供了此代码的更新:blog.liip.ch/archive/2008/09/10/…
  • 不适用于" onfocus="alert(1)" autofocus="
【解决方案3】:

最好和最安全的方法是使用 HTML Purifier。按照此链接获取有关将其与 Zend Framework 一起使用的一些提示。

HTML Purifier with Zend Framework

【讨论】:

  • 但是该死的图书馆是臃肿的。
  • 它可能会臃肿,但当你真的需要核选项将其过滤掉时,它是最好的。
【解决方案4】:

我也有类似的问题。我需要用户使用出色的所见即所得编辑器(Redactorjs!)将 html 内容提交到个人资料页面,我编写了以下函数来清理提交的 html:

    <?php function filterxss($str) {
//Initialize DOM:
$dom = new DOMDocument();
//Load content and add UTF8 hint:
$dom->loadHTML('<meta http-equiv="content-type" content="text/html; charset=utf-8">'.$str);
//Array holds allowed attributes and validation rules:
$check = array('src'=>'#(http://[^\s]+(?=\.(jpe?g|png|gif)))#i','href'=>'|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i');
//Loop all elements:
foreach($dom->getElementsByTagName('*') as $node){
    for($i = $node->attributes->length -1; $i >= 0; $i--){
        //Get the attribute:
        $attribute = $node->attributes->item($i);
        //Check if attribute is allowed:
        if( in_array($attribute->name,array_keys($check))) {
            //Validate by regex:    
            if(!preg_match($check[$attribute->name],$attribute->value)) { 
                //No match? Remove the attribute
                $node->removeAttributeNode($attribute); 
            }
        }else{
            //Not allowed? Remove the attribute:
            $node->removeAttributeNode($attribute);
        }
    }
}
var_dump($dom->saveHTML()); } ?>

$check 数组包含所有允许的属性和验证规则。也许这对你们中的一些人有用。我还没有测试,所以欢迎提示

【讨论】:

    【解决方案5】:
    function clean($data){
        $data = rawurldecode($data);
        return filter_var($data, FILTER_SANITIZE_SPEC_CHARS);
    }
    

    【讨论】:

    • 不起作用。但$data = filter_var($_GET['data'], FILTER_SANITIZE_STRING); 有效。
    【解决方案6】:

    htmlspecialchars() 非常适合过滤以 html 表单显示的用户输入。

    【讨论】:

      【解决方案7】:

      根据 www.mcafeesecure.com 对于易受跨站脚本 (XSS) 过滤功能的一般解决方案可以是:

      function xss_cleaner($input_str) {
          $return_str = str_replace( array('<','>',"'",'"',')','('), array('&lt;','&gt;','&apos;','&#x22;','&#x29;','&#x28;'), $input_str );
          $return_str = str_ireplace( '%3Cscript', '', $return_str );
          return $return_str;
      }
      

      【讨论】:

      • 先前接受且高度赞成的答案提供了一个干净而简短的解决方案。您的解决方案对该答案有何补充?查看metaSO questionJon Skeet: Coding Blog,了解如何给出正确答案。
      【解决方案8】:

      以上所有方法都不允许保留一些标签,如&lt;a&gt;&lt;table&gt; 等。有一个终极解决方案http://sourceforge.net/projects/kses/ Drupal 使用它

      【讨论】:

        【解决方案9】:

        我正在通过网络收集大部分问题并为所有问题组合步进过滤器。

        经过一些测试,它看起来很完美:

        
        /*
        * Total XSS preventer class by Full-R
        *
        */
        
        final class xCleaner {
        
            public static function clean( string $html ): string {
        
                return self::cleanXSS(
        
                    preg_replace(
        
                        [
        
                            '/\s?<iframe[^>]*?>.*?<\/iframe>\s?/si',
                            '/\s?<style[^>]*?>.*?<\/style>\s?/si',
                            '/\s?<script[^>]*?>.*?<\/script>\s?/si',
                            '#\son\w*="[^"]+"#',
        
                        ],
        
                        [
                            '',
                            '',
                            ''
                        ],
        
                        $html
        
                    )
        
                );
        
            }
        
            protected static function hexToSymbols( string $s ): string {
        
                return html_entity_decode($s, ENT_XML1, 'UTF-8');
        
            }
        
            protected static function escape( string $s, string $m = 'attr' ): string {
        
                preg_match_all('/data:\w+\/([a-zA-Z]*);base64,(?!_#_#_)([^)\'"]*)/mi', $s, $b64, PREG_OFFSET_CAPTURE);
        
                if( count( array_filter( $b64 ) ) > 0 ) {
        
                    switch( $m ) {
        
                        case 'attr':
        
                            $xclean = self::cleanXSS(
        
                                                urldecode(
        
                                                    base64_decode(
        
                                                        $b64[ 2 ][ 0 ][ 0 ]
        
                                                    )
        
                                                )
        
                                        );
        
                            break;
        
                        case 'tag':
        
                            $xclean = self::cleanTagInnerXSS(
        
                                                urldecode(
        
                                                    base64_decode(
        
                                                        $b64[ 2 ][ 0 ][ 0 ]
        
                                                    )
        
                                                )
        
                                        );
        
                            break;
        
                    }
        
                    return substr_replace(
        
                        $s,
        
                        '_#_#_'. base64_encode( $xclean ),
        
                        $b64[ 2 ][ 0 ][ 1 ],
        
                        strlen( $b64[ 2 ][ 0 ][ 0 ] )
        
                    );
        
                }
                else {
        
                    return $s;
        
                }
        
            }
        
            protected static function cleanXSS( string $s ): string {
        
                // base64 injection prevention
                $st = self::escape( $s, 'attr' );
        
                return preg_replace([
        
                        // JSON unicode
                        '/\\\\u?{?([a-f0-9]{4,}?)}?/mi',                                                                    // [1] unicode JSON clean
        
                        // Data b64 safe
                        '/\*\w*\*/mi',                                                                                            // [2] unicode simple clean
        
                        // Malware payloads
                        '/:?e[\s]*x[\s]*p[\s]*r[\s]*e[\s]*s[\s]*s[\s]*i[\s]*o[\s]*n[\s]*(:|;|,)?\w*/mi',    // [3]  (:expression) evalution
                        '/l[\s]*i[\s]*v[\s]*e[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi',         // [4]  (livescript:) evalution
                        '/j[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi',                                 // [5]  (jscript:) evalution
                        '/j[\s]*a[\s]*v[\s]*a[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi',       // [6]  (javascript:) evalution
                        '/b[\s]*e[\s]*h[\s]*a[\s]*v[\s]*i[\s]*o[\s]*r[\s]*(:|;|,)?\w*/mi',                     // [7]  (behavior:) evalution
                        '/v[\s]*b[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t[\s]*(:|;|,)?\w*/mi',                      // [8]  (vsbscript:) evalution
                        '/v[\s]*b[\s]*s[\s]*(:|;|,)?\w*/mi',                                                              // [9]  (vbs:) evalution
                        '/e[\s]*c[\s]*m[\s]*a[\s]*s[\s]*c[\s]*r[\s]*i[\s]*p[\s]*t*(:|;|,)?\w*/mi',        // [10] (ecmascript:) possible ES evalution
                        '/b[\s]*i[\s]*n[\s]*d[\s]*i[\s]*n[\s]*g*(:|;|,)?\w*/mi',                                 // [11] (-binding) payload
                        '/\+\/v(8|9|\+|\/)?/mi',                                                                          // [12] (UTF-7 mutation)
        
                        // Some entities
                        '/&{\w*}\w*/mi',                                                                                   // [13] html entites clenup
                        '/&#\d+;?/m',                                                                                      // [14] html entites clenup
        
                        // Script tag encoding mutation issue
                        '/\¼\/?\w*\¾\w*/mi',                                                                         // [21] mutation KOI-8
                        '/\+ADw-\/?\w*\+AD4-\w*/mi',                                                         // [22] mutation old encodings
        
                        '/\/*?%00*?\//m',
        
                        // base64 escaped
                        '/_#_#_/mi',                                                                                       // [23] base64 escaped marker cleanup
                     
                    ],
        
                    // Replacements steps :: 23
                    ['&#x$1;', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
        
                    str_ireplace(
        
                        ['\u0', '&colon;', '&tab;', '&newline;'],
                        ['\0', ':', '', ''],
        
                    // U-HEX prepare step
                    self::hexToSymbols( $st ))
        
                );
        
            }
        
        }
        
        

        您还可以添加整洁的标记更正以使 HTML 有效。

        【讨论】:

          【解决方案10】:

          我找到了解决德语变音符号帖子问题的方法。为了完全清理(杀死)帖子,我对传入的数据进行编码:

              *$data = utf8_encode($data);
              ... function ...*
          

          最后我解码输出以获得正确的符号:

              *$data = utf8_decode($data);*
          

          现在帖子通过过滤功能,我得到了正确的结果...

          【讨论】:

            【解决方案11】:

            尝试使用 Clean XSS

            xss_clean($data): "><script>alert(String.fromCharCode(74,111,104,116,111,32,82,111,98,98,105,101))</script>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-05-05
              • 2013-12-20
              • 2011-09-18
              • 2012-03-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-11-01
              相关资源
              最近更新 更多