用户定义的 HTML
您正试图通过将您不想允许的内容列入黑名单来清理用户输入。不幸的是,特别是考虑到 HTML5 的选项列表非常大,很容易错过一些东西。遗漏一些东西会导致一个潜在的危险 XSS 漏洞,这是你真的不想要的。从我的脑海中挑选一些随机的例子:
- 你知道 SVG 标签可以在某些(有限的)情况下执行脚本吗?
- 在您
on
禁止的事件属性列表中,您是否确定并获得onbounce
过时(但仍然可用)选取框标签的事件属性?
- 您是否要确保并跟踪可能在未来 X 年内推出的 HTML 规范的任何更改,以防万一添加危险标签/事件?
可能有很多陷阱,以至于几乎不可能使用黑名单保护输入。此外,您从错误的角度处理问题。在安全方面,您要开始使用的方法是最小特权原则。与其问“我应该阻止我的用户做什么”,不如问“我应该允许他们做什么?”更安全。因此,您需要一个两步过程:
1. 强大的解析器。 你需要一个非常健壮的解析器。这非常困难,因为浏览器在解析 HTML 时非常宽容。如果攻击者给你错误的 HTML 并且你的解析器停止尝试并说:“这里没有 HTML - 你很安全!”,但浏览器接受相同的输入,猜测 HTML 应该是什么,然后结束有了恶意,你就有了 XSS 漏洞。这听起来更加困难,因为不同的浏览器在处理 HTML 输入时可以应用不同的“更正”,这使得可靠地解析 HTML 已经很困难的任务变得更加困难。
作为浏览器快速播放 HTML 的示例,您可以将此 HTML 保存到文件中并将其加载到浏览器中:
<table><img src="1" <table onerror="alert(1)"
<p>hi</p></table>
如果你用 Chrome 加载它并检查页面上的元素,你会看到浏览器实际上呈现了这个(可能取决于你的版本):
<img src="1" <table="" onerror="alert(1)" <p="">hi<p></p><table></table>
table
这是一个带有活动 XSS 有效负载的图像标签(由于标签和p
转变成无意义的属性这一事实稍微混淆了它)、文字字符串hi
、空p
标签和空table
标签。最终结果与输入完全不同。我没有非常努力地隐藏有效负载,但是您的解析器会以同样的方式理解它吗?也许您的解析器会尝试忽略img
标签内的table
标签,因为任何不在标签中的东西在td
技术上都是非法的。也许您的解析器会被标签<table
内部混淆img
并忽略onerror
因为从技术上讲,表格标签没有事件。但事实证明,这些都没有阻止浏览器执行我的 javascript 有效负载。你的解析器会捕捉到它吗?
2. 将允许的标签和属性列入白名单一旦您解析了用户的 HTML,您就不想与黑名单进行比较并删除不允许的标签/属性。相反,您想与白名单进行比较,并删除您没有特别审查和批准为安全的任何内容。这使您的安全性更加稳固,而且 - 老实说 - 您真的希望您的用户使用该marquee
标签吗?
最重要的是,构建一个健壮的 HTML 解析器非常困难。如果您尝试自己做,您将花费大量时间并且可能会犯很多错误。在正常情况下,您最好找到一个支持良好的第三方库来使用。
替代建议
我通常建议的另一种策略是根本不让用户使用 HTML。相反,允许使用更有限的语言(如降价用于在堆栈溢出中编写问题和答案)。更有限的语言规范使得编写解析器更容易,更不容易出错,并且将 Markdown 转换为 HTML 的过程更容易保证“安全性”(注意:更容易,不能保证 - Markdown 到 HTML 转换器仍然会偶尔遭受 XSS漏洞)。有一个轻微的缺点是它限制了用户拥有的格式化选项的种类(尽管在大多数情况下我并不认为这是一个缺点),但你也有一个很好的优势,即降价解析器和 HTML 转换器可以广泛使用多种语言。像这样更有限的选择通常是可用性和安全性之间的良好折衷。您甚至可以添加为用户构建降价的 WYSIWYG 编辑器。