这组正则表达式是否完全防止跨站点脚本?

时间:2008-10-12 16:16:41

标签: regex security xss

下面的代码无法捕获哪些危险的例子?

编辑:在一些评论后,我添加了另一行,请在下面评论。请参阅Vinko在David Grant的回答中的评论。到目前为止,只有Vinko回答了这个问题,该问题要求具体的例子可以通过这个功能。 Vinko提供了一个,但我编辑了代码来关闭那个洞。如果你们中的另一个人能够想到另一个具体的例子,那么你将得到我的投票!

public static string strip_dangerous_tags(string text_with_tags)
{
    string s = Regex.Replace(text_with_tags, @"<script", "<scrSAFEipt", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"</script", "</scrSAFEipt", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"<object", "</objSAFEct", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"</object", "</obSAFEct", RegexOptions.IgnoreCase);
    // ADDED AFTER THIS QUESTION WAS POSTED
    s = Regex.Replace(s, @"javascript", "javaSAFEscript", RegexOptions.IgnoreCase);

    s = Regex.Replace(s, @"onabort", "onSAFEabort", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onblur", "onSAFEblur", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onchange", "onSAFEchange", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onclick", "onSAFEclick", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"ondblclick", "onSAFEdblclick", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onerror", "onSAFEerror", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onfocus", "onSAFEfocus", RegexOptions.IgnoreCase);

    s = Regex.Replace(s, @"onkeydown", "onSAFEkeydown", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onkeypress", "onSAFEkeypress", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onkeyup", "onSAFEkeyup", RegexOptions.IgnoreCase);

    s = Regex.Replace(s, @"onload", "onSAFEload", RegexOptions.IgnoreCase);

    s = Regex.Replace(s, @"onmousedown", "onSAFEmousedown", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onmousemove", "onSAFEmousemove", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onmouseout", "onSAFEmouseout", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onmouseup", "onSAFEmouseup", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onmouseup", "onSAFEmouseup", RegexOptions.IgnoreCase);

    s = Regex.Replace(s, @"onreset", "onSAFEresetK", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onresize", "onSAFEresize", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onselect", "onSAFEselect", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onsubmit", "onSAFEsubmit", RegexOptions.IgnoreCase);
    s = Regex.Replace(s, @"onunload", "onSAFEunload", RegexOptions.IgnoreCase);

    return s;
}

11 个答案:

答案 0 :(得分:48)

永远不够 - 白名单,不要黑名单

例如,javascript:伪URL可以使用HTML实体进行模糊处理,您忘记了<embed>并且IE中存在危险的CSS属性,如behaviorexpression

countless ways来逃避过滤器,这种方法必将失败。即使您今天发现并阻止了所有可能的漏洞利用,未来也可能会添加新的不安全元素和属性。

保护HTML只有两种好方法:

  • 将每个<替换为&lt;,将其转换为文字 如果您想允许用户输入带格式的文本,您可以使用自己的标记(例如像SO那样的降价)。

  • 将HTML解析为DOM,检查每个元素和属性,并删除未列入白名单的所有内容 您还需要检查允许的属性内容,例如href(确保URL使用安全协议,阻止所有未知协议)。
    一旦清理了DOM,就可以从中生成新的有效HTML。永远不要像在文本上那样处理HTML,因为无效的标记,注释,实体等很容易欺骗你的过滤器。

还要确保您的网页声明其编码,因为有利用浏览器自动检测错误编码的漏洞利用。

答案 1 :(得分:10)

最好将所有<转换为&lt;,将所有>转换为&gt;,然后将可接受的代码转换回来。换句话说,白名单,不要黑名单。

答案 2 :(得分:7)

正如David所说,没有简单的方法可以保护只有一些正则表达式,你总是可以忘记一些东西,比如javascript:在你的情况下。您最好在输出时转义HTML实体。关于实现此目的的最佳方式有很多讨论,具体取决于您实际需要允许的内容,但您的功能不够

杰夫已经谈过这个here

答案 3 :(得分:4)

<a href="javascript:document.writeln('on' + 'unload' + ' and more malicious stuff here...');">example</a>

任何时候你都可以在文件上写一个字符串,一扇大门就会打开。

有无数的地方可以将恶意内容注入HTML / JavaScript。出于这个原因,Facebook最初并未在其应用程序平台中使用JavaScript。他们的解决方案是稍后实现一个标记/脚本编译器,允许他们认真地过滤掉坏的东西。

如上所述,将一些标签和属性列入白名单并删除其他所有内容。不要将一些已知的恶意属性列入黑名单,并允许其他所有内容。

答案 4 :(得分:3)

虽然我不能提供一个具体的例子,为什么不这样做,我会继续前进并直截了当地说不。这更多是关于本金的。正则表达式是一个了不起的工具,但它们只应用于某些问题。它们非常适合数据匹配和搜索。

然而,它们不是一个安全的好工具。它很容易弄乱正则表达式并且只是部分正确。黑客可以在一个糟糕甚至构造良好的正则表达式中找到许多摆动空间。我会尝试另一种方法来阻止跨站点脚本。

答案 5 :(得分:3)

http://ha.ckers.org/xss.html查看XSS备忘单,这不是一个完整的清单,但是一个良好的开端。

想到的是&lt; img src =“http://badsite.com/javascriptfile”/&gt;

你也忘记了onmouseover和样式标签。

最简单的方法是实体转义。如果向量无法在第一时间正确呈现,则不完整的黑名单将无关紧要。

答案 6 :(得分:3)

作为攻击的一个例子,通过这个:

  <div style="color: expression('alert(4)')">

无耻插头: Caja项目定义了HTML元素和属性的白名单,以便它可以控制HTML中脚本的执行方式和时间。

http://code.google.com/p/google-caja/查看项目 并且白名单是JSON文件 http://code.google.com/p/google-caja/source/browse/#svn/trunk/src/com/google/caja/lang/htmlhttp://code.google.com/p/google-caja/source/browse/#svn/trunk/src/com/google/caja/lang/css

答案 7 :(得分:3)

我仍然没有弄清楚为什么开发人员希望通过正则表达式替换将错误的输入按到良好的输入。除非您的网站是博客并且需要允许嵌入的html或javascript或任何其他类型的代码,否则拒绝错误的输入并返回错误。古老的谚语是Garbage In - Garbage Out,你为什么要拿一个漂亮的热气腾腾的便便堆来让它食用?

如果您的网站没有国际化,为什么要接受任何unicode?

如果您的网站只进行POST,为什么要接受任何URL编码值?

为什么接受任何十六进制?为什么接受html实体?用户输入的内容&#39;&amp;#x0A&#39;或者&#39;&amp; quot;&#39; ?

对于正则表达式,使用它们很好,但是,您不必为完整的攻击字符串编写单独的正则表达式。只需几个构造良好的正则表达式模式就可以拒绝许多不同的攻击签名:

patterns.put("xssAttack1", Pattern.compile("<script",Pattern.CASE_INSENSITIVE) );
patterns.put("xssAttack2", Pattern.compile("SRC=",Pattern.CASE_INSENSITIVE) );
patterns.put("xssAttack3", Pattern.compile("pt:al",Pattern.CASE_INSENSITIVE) );
patterns.put("xssAttack4", Pattern.compile("xss",Pattern.CASE_INSENSITIVE) );

<FRAMESET><FRAME SRC="javascript:alert('XSS');"></FRAMESET>
<DIV STYLE="width: expression(alert('XSS'));">
<LINK REL="stylesheet" HREF="javascript:alert('XSS');">
<IMG SRC="jav   ascript:alert('XSS');">    // hmtl allows embedded tabs...
<IMG SRC="jav&#x0A;ascript:alert('XSS');"> // hmtl allows embedded newline...
<IMG SRC="jav&#x0D;ascript:alert('XSS');"> // hmtl allows embedded carriage return...

请注意,我的模式不是完整的攻击特征,只是足以检测该值是否为恶意。用户不太可能输入“SRC =&#39;或者&#39; pt:al&#39;这允许我的正则表达式模式检测其中包含任何这些令牌的未知攻击。

许多开发人员会告诉您,您无法使用黑名单保护网站。由于攻击集是无限的,所以基本上是正确的,但是,如果您使用基于令牌构建的黑名单解析整个请求(参数,参数值,标题,cookie),您将能够找出什么是攻击什么是有效的。请记住,攻击者很可能会通过工具对您进行射击攻击。如果你已经正确地强化了你的服务器,他将无法知道你正在运行什么环境,并且必须使用漏洞利用列表。如果他对你不满,请将攻击者或他的IP放在隔离列表上。如果他有一个具有50k攻击的工具准备好攻击你的网站,如果你为每次违规隔离他的id或ip 30分钟,他需要多长时间?不可否认,如果攻击者使用僵尸网络来复用他的攻击,那么仍然存在暴露。你的网站仍然是一个更难以破解的金块。

现在检查了整个恶意内容请求,您现在可以使用白名单类型检查长度,参考/逻辑,命名来确定请求的有效性

不要忘记实施某种CSRF保护。也许是一个蜂蜜令牌,并检查先前请求中的用户代理字符串,看它是否已更改。

答案 8 :(得分:2)

空白会让你变得脆弱。 Read this

答案 9 :(得分:1)

白名单的另一票。但看起来你正在以错误的方式解决这个问题。 I 的方式是将HTML解析为标记树。如果要解析的标记位于白名单中,请为其指定树节点并进行解析。它的属性也是如此。

删除了丢弃的属性。其他所有内容都是HTML转义的文字内容。

这条路线的好处是因为你有效地重新生成了所有的标记,它都是完全有效的标记! (当人们发表评论并搞砸了验证/设计时,我讨厌它。)

重新“我不能列入白名单”(段落):黑名单是一种维护繁重的方法。你必须密切关注新的漏洞,并确保你的覆盖。这是悲惨的存在。 只需执行一次就可以再次触摸它。

答案 10 :(得分:1)

从不同的角度来看,当有人想要提交“javascript”或“functionload”或“visionblurred”时会发生什么?这种情况可能在大多数地方出现,原因有很多......根据我的理解,这些将成为'javaSAFEscript','functionSAFEload'和'visionSAFEblurred'(!!)。

如果这可能适用于您,并且您坚持使用黑名单方法,请务必使用完全匹配的正则表达式以避免让用户烦恼。换句话说,处于安全性和可用性之间的最佳点,尽可能少地妥协。