如何通过URL阻止XSS?

时间:2015-06-30 14:04:20

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

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

最近,我遇到了一个非持久性的用户,用户只需在页面上某处显示URL的URL上发送脚本即可。就我而言,它是一个链接标记。

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

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

问题在于有人发送链接,例如:

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

可能是%27(单引号)和%22(双引号)将关闭标记,因此允许用户输入脚本等。

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

顺便说一句,我使用的是PHP,并且更喜欢使用原生函数。

3 个答案:

答案 0 :(得分:1)

我知道你说你更喜欢原生功能,但我一般都能找到摆脱大多数解决方案的方法。但是,这个库绝对可以完成这项工作。如果你执行大量的执行(每个请求大于1000,会降低你的页面速度),这有点慢。

http://htmlpurifier.org/

答案 1 :(得分:1)

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

答案 2 :(得分:-1)

像这样: 检查这个答案,它是具有以下功能的答案: 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;
    }