用户生成的 HTML 的安全风险?

信息安全 html html-5
2021-08-17 18:26:05

我正在创建一个允许人们上传 HTML 内容的网站。

目前这些是被禁止的标签:

<script></script>
<iframe>
<object>
<embed>
<style></style>
All on= attributes, i'm not gonna list them all there are like 70 of them

我不希望用户使用任何 JavaScript 或放置任何会影响页面上其他标签的代码,因此也没有样式标签。

在使用户能够生成 HTML 而不会影响页面上的其他内容时,我是否需要注意其他任何标签?

4个回答

用户定义的 HTML

您正试图通过将您不想允许的内容列入黑名单来清理用户输入。不幸的是,特别是考虑到 HTML5 的选项列表非常大,很容易错过一些东西。遗漏一些东西会导致一个潜在的危险 XSS 漏洞,这是你真的不想要的。从我的脑海中挑选一些随机的例子:

  1. 你知道 SVG 标签可以在某些(有限的)情况下执行脚本吗?
  2. 在您on禁止的事件属性列表中,您是否确定并获得onbounce过时(但仍然可用)选取框标签的事件属性?
  3. 您是否要确保并跟踪可能在未来 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 编辑器。

目前这些是被禁止的标签:

除了已经发布的内容外,请确保禁止意味着“不要让用户保存数据”而不是 “删除被禁止的内容并保存其余内容”

一个例子:

Input:
Hi there, here is my <script>alert('scary script')</script>, will I be shown?  
Filtered:  
Hi there, here is my alert('scary script'), will I be shown?

删除禁止标签似乎很好?毕竟,我们阻止了脚本标签做一些愚蠢的事情。但是如果我改为输入这个呢?

Input:  
Hi there, here is my <scr<script>ipt>alert('scary script')</scr<script>ipt>, will I be shown?  
Filtered:  
Hi there, here is my <script>alert('scary script')</script>, will I be shown? 

哎呀!删除<script>标签使我的字符串成为有效攻击。

我使用这个技巧在一个早已被遗忘的社交网络上制作了一个看起来更酷的个人资料页面,允许您添加一些自定义 HTML。过滤 HTML很难,尝试找到其他方法来实现您的目标。

撇开我仍然可以让 XSS 越过这个黑名单的所有方法(其他答案在很大程度上已经涵盖),允许任意 HTML 仍然非常危险。例如,如果用户可以控制style=属性(你说你阻止了样式标签,但没有关于内联属性),甚至只是可以访问旧的定位属性(如果你让用户提供 HTML,浏览器将不得不允许有些无效的输入),攻击者基本上可以使用恶意内容覆盖整个页面,例如网络钓鱼登录表单、(假)安全警告/勒索软件勒索消息、可怕的图像或视频等。恶意用户还可以找到对浏览器的渲染引擎产生不利影响的 HTML (例如消耗大量 RAM 和/或永远渲染和使用所有 CPU;并非所有攻击都旨在控制系统)并在任何可能的地方向 HTML 发送垃圾邮件。

唯一好的选择是使用一种安全的布局语言,该语言由经过良好测试的库翻译成 HTML(各种形式的 markdown 或 bbcode 都是为此而设计的)。如果您必须允许 HTML,请通过将特定标签列入白名单,并在这些标签中将特定属性列入白名单(如有必要仅允许这些属性的特定值),并丢弃任何不匹配的内容。然后,在您的过滤器进行的每次更改后重新测试,以确保过滤器自己的更改不会引入恶意输入。

用户生成的内容将被解释/解析和公开显示,存在重大风险。XSS 攻击等可能发生在用户能够通过您的清理功能偷偷标记的情况下,并且浏览器会解释您必须设计的许多变体。

推荐?根本不允许标签。如果必须,那里有库(服务器端)尝试这样做,并且可能会完成大量工作以避免可能存在的清理绕过。

就你的问题而言:

在使用户能够生成 html 而不会影响页面上的其他内容时,我是否需要注意其他任何标签?

最好的方法是假设所有标签都受到关注,并且更多地决定您想要的特定标签(正如用户 Ghedipunk 建议的那样)。这是因为标签可以以独特的,有时是不可预见的方式被利用。这可以从特定的浏览器实现怪癖到不太常见的标签使用。删除所有遵循 HTML 标记模式的输入(特定标记除外)比尝试阻止特定标记要容易得多。

有多种方法可以实现这一点,从最简单的方法到更高级的方法(实际的 DOM 处理)。如果您尝试使用黑名单方法,您将不断追踪不同绕过攻击的变体以及您认为安全或忘记包含的各种标签的意外使用。

我相信那里已经存在一个图书馆,它以更先进和更安全的方式完成了此类操作。我的建议是为您正在开发的任何平台寻找那些。