【问题标题】:How to prevent XSS via URL?如何通过 URL 防止 XSS?
【发布时间】:2015-09-17 09:10:04
【问题描述】:

我熟悉通常的持久性 XSS,其中来自用户输入的内容应该在输出到模板(html 实体)的途中被转义。

最近,我遇到了一个非持久性的,用户可以在 URL 上发送脚本,该 URL 显示在页面上的某处。在我的例子中,它是一个链接标签。

所以我有以下使用当前 URL 的链接标记。

<link rel="next" href="{current_url}" />

问题是当有人发送如下链接时:

www.example.com/?%27;alert...

可以是 %27(单引号)和 %22(双引号)来关闭标签,从而允许用户输入脚本等。

我知道防止 XSS 的常用方法是使用 html 实体。在这种情况下,这不会破坏 URL 吗?是否可以使用 url 编码代替?

顺便说一句,我正在使用 PHP,并且更喜欢使用本机函数。

【问题讨论】:

  • 您在这里使用哪个模板系统?它有 url 编码过滤器吗?
  • 这是Smarty吗? Then you could use a filter 喜欢:{current_url|escape:'url'}.
  • 它是“用户输入”,只是在url 而不是在“帖子”字段等中。您验证它并确定它是否是您期望的并且有效?它永远不会被执行?
  • 不,它并不聪明。是的,它是用户输入,可以打破标签并允许用户添加脚本标签。
  • 因为它是 'user input' ,它总是不受信任的,那么如果你总是用 'htmlentities' 或其他确保它无法执行的编码输出它,那么它会安全吗?跨度>

标签: javascript php xss html-entities url-encoding


【解决方案1】:

所有来自用户的内容都应该被转义,无论是来自 URL 还是来自数据库。在这种情况下,您只需进行 URL 编码而不是 HTML 实体。您的模板引擎可能已经足够聪明,可以为进入 HTML 属性的值执行此操作。

【讨论】:

  • 这个答案是最有帮助的。我最终对查询参数进行了 url 编码(对 PHP 使用 http_build_query)。
【解决方案2】:

我知道你说过你更喜欢原生函数,但我通常能够找到击败大多数解决方案的方法。然而,这个库绝对可以胜任。如果您运行大量执行,它会有点慢(每个请求> 1000 会减慢您的页面速度)。

http://htmlpurifier.org/

【讨论】:

    【解决方案3】:

    像这样: 检查这个答案,它是具有以下功能的答案: XSS filtering function in PHP

     function xss_clean($data)
        {
            /*
             * Function to clean a string to prevent XSS attack.
             */
    
            // Fix &entity\n;
            $data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
            $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
            $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
    
            // decode
            $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;
        }
    

    【讨论】:

      猜你喜欢
      • 2021-08-04
      • 1970-01-01
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-26
      相关资源
      最近更新 更多