如何在 ASP.NET MVC 5 中进行白名单 HTML 编码?
How to do white-listed HTML encoding in ASP.NET MVC 5?
我正在为我的一个项目开发一个迷你 CMS 模块,允许用户在 markdown 中编辑内容。我正在使用 markdown-it
来解析和显示预览。
我一直在思考如何将输入发送到服务器,以及如何将其存储在数据库中。我得出的结论是避免在服务器端重复 markdown 解析,并将 markdown 和解析后的 HTML 发送到服务器。我认为现在增加的开销很小,即使是在编辑繁重的网站上也是如此。
所以在最后阶段我仍然需要验证发送到服务器的 HTML,因为它可能是系统的安全瓶颈。我已经阅读了很多关于 Microsoft 的 AntiXSS 实现的信息,以及它是如何(或曾经)无法用于此类场景的,因为它太贪婪了。例如,我发现 this article 甚至还有一个辅助代码(使用 HTMLAgilityPack)来提供可用的清理实现。
遗憾的是,我没有找到比 2013 年更新的关于此主题的内容。我想问一下目前如何在允许的标签和属性的情况下进行适当的 HTML 编码,但仍然可以免受任何类型的 XSS 攻击?是否还需要像文章中这样的代码,或者有没有内置的解决方案?
此外,如果我选择的客户端降价解析不可行,还有哪些其他选择?我想避免的是在客户端和服务器上复制各种降价逻辑。例如我为markdown-it
等准备了几个自定义扩展
如果您允许在客户端编辑 html 并将其存储到服务器,那么您基本上就是打开了一堆蠕虫。这适用于客户端 html 编辑器,也适用于您想要保存从降价生成的 html 的用例。问题是恶意用户可能会向您的后端发送任何 html,而不仅仅是可以从降价中实际生成的。 Html 这种情况下的代码将是纯用户输入,因此不得信任。
假设您要实现标签和标签属性的白名单,即 HTMLAgilityPack 方式。考虑 html 中的简单 link。您显然希望允许 <a>
标记以及 href
属性,以便 link 成为可能。但是 <a href="javascript:alert(1)">
呢?它很容易受到明显的 XSS 攻击,这只是一个例子,它会以多种方式受到攻击。
更糟糕的是,您可能希望在服务器往返之前在客户端上呈现 user-given html(类似于预览),并将其保存到您的数据库并在下载后呈现它再次。为此,您必须关闭请求验证和自动编码,因为它们会使这成为不可能。
所以您有几个选项可以实际用于防止 XSS。
Client-side 消毒:您可以使用 Google Caja (only the Javascript library, not the whole thing) to remove Javascript from any html content. The way this would work is before displaying any such html (before previewing html on the client, or before displaying html downloaded from the server), you would run it through Caja, and that would remove any Javascript, thus eliminating XSS. It works reasonably well in my experience, it removes Javascript from CSS too, and also the trivial ones like href, src, a script tag, event attributes (onclick, onmouseover, etc). Another similar library is HTML Purify 的 client-side 消毒剂,但这只适用于新的浏览器,并且不会从 CSS 中删除 Javascript(因为这在较新的浏览器中不起作用)。
Server-side sanitization:您也可以在服务器端正确使用 Caja,但这可能太难维护了用例,而且如果只实现了这一点,在客户端上预览(没有服务器往返)仍然容易受到 DOM XSS 的攻击。
Content-Security-Policy:您可以使用 Content-Security-Policy
响应 header 禁用所有内联 Javascript在您的网站上。一个缺点是它会对您的 client-side 体系结构产生影响(显然您根本无法使用内联 Javascript),而且浏览器支持有限,在不受支持的浏览器中,您的页面实际上容易受到攻击跨站脚本。不过现在主流浏览器的最新版本都支持Content-Security-Policy,确实是个不错的选择
单独的框架:您可以从不同的来源(即不同的子域)提供不安全的 html 并接受 XSS 的风险那个起源。但是,cross-frame 通信仍然是一个问题,身份验证 and/or CSRF 也将是一个问题,具体取决于解决方案。这是一种老派的方式,上面的选项可能更适合您的用例。
您也可以结合使用这些方法进行纵深防御。
我最终使用了文章中的代码。我做了一个重要的改变,我从白名单中完全删除了 style
属性。我不需要它们,我允许的样式可以通过 类 实现。此外,style
属性也很危险并且很难 encode/escape 正确。现在我觉得代码对于我目前的目的来说已经足够安全了。
我正在为我的一个项目开发一个迷你 CMS 模块,允许用户在 markdown 中编辑内容。我正在使用 markdown-it
来解析和显示预览。
我一直在思考如何将输入发送到服务器,以及如何将其存储在数据库中。我得出的结论是避免在服务器端重复 markdown 解析,并将 markdown 和解析后的 HTML 发送到服务器。我认为现在增加的开销很小,即使是在编辑繁重的网站上也是如此。
所以在最后阶段我仍然需要验证发送到服务器的 HTML,因为它可能是系统的安全瓶颈。我已经阅读了很多关于 Microsoft 的 AntiXSS 实现的信息,以及它是如何(或曾经)无法用于此类场景的,因为它太贪婪了。例如,我发现 this article 甚至还有一个辅助代码(使用 HTMLAgilityPack)来提供可用的清理实现。
遗憾的是,我没有找到比 2013 年更新的关于此主题的内容。我想问一下目前如何在允许的标签和属性的情况下进行适当的 HTML 编码,但仍然可以免受任何类型的 XSS 攻击?是否还需要像文章中这样的代码,或者有没有内置的解决方案?
此外,如果我选择的客户端降价解析不可行,还有哪些其他选择?我想避免的是在客户端和服务器上复制各种降价逻辑。例如我为markdown-it
等准备了几个自定义扩展
如果您允许在客户端编辑 html 并将其存储到服务器,那么您基本上就是打开了一堆蠕虫。这适用于客户端 html 编辑器,也适用于您想要保存从降价生成的 html 的用例。问题是恶意用户可能会向您的后端发送任何 html,而不仅仅是可以从降价中实际生成的。 Html 这种情况下的代码将是纯用户输入,因此不得信任。
假设您要实现标签和标签属性的白名单,即 HTMLAgilityPack 方式。考虑 html 中的简单 link。您显然希望允许 <a>
标记以及 href
属性,以便 link 成为可能。但是 <a href="javascript:alert(1)">
呢?它很容易受到明显的 XSS 攻击,这只是一个例子,它会以多种方式受到攻击。
更糟糕的是,您可能希望在服务器往返之前在客户端上呈现 user-given html(类似于预览),并将其保存到您的数据库并在下载后呈现它再次。为此,您必须关闭请求验证和自动编码,因为它们会使这成为不可能。
所以您有几个选项可以实际用于防止 XSS。
Client-side 消毒:您可以使用 Google Caja (only the Javascript library, not the whole thing) to remove Javascript from any html content. The way this would work is before displaying any such html (before previewing html on the client, or before displaying html downloaded from the server), you would run it through Caja, and that would remove any Javascript, thus eliminating XSS. It works reasonably well in my experience, it removes Javascript from CSS too, and also the trivial ones like href, src, a script tag, event attributes (onclick, onmouseover, etc). Another similar library is HTML Purify 的 client-side 消毒剂,但这只适用于新的浏览器,并且不会从 CSS 中删除 Javascript(因为这在较新的浏览器中不起作用)。
Server-side sanitization:您也可以在服务器端正确使用 Caja,但这可能太难维护了用例,而且如果只实现了这一点,在客户端上预览(没有服务器往返)仍然容易受到 DOM XSS 的攻击。
Content-Security-Policy:您可以使用
Content-Security-Policy
响应 header 禁用所有内联 Javascript在您的网站上。一个缺点是它会对您的 client-side 体系结构产生影响(显然您根本无法使用内联 Javascript),而且浏览器支持有限,在不受支持的浏览器中,您的页面实际上容易受到攻击跨站脚本。不过现在主流浏览器的最新版本都支持Content-Security-Policy,确实是个不错的选择单独的框架:您可以从不同的来源(即不同的子域)提供不安全的 html 并接受 XSS 的风险那个起源。但是,cross-frame 通信仍然是一个问题,身份验证 and/or CSRF 也将是一个问题,具体取决于解决方案。这是一种老派的方式,上面的选项可能更适合您的用例。
您也可以结合使用这些方法进行纵深防御。
我最终使用了文章中的代码。我做了一个重要的改变,我从白名单中完全删除了 style
属性。我不需要它们,我允许的样式可以通过 类 实现。此外,style
属性也很危险并且很难 encode/escape 正确。现在我觉得代码对于我目前的目的来说已经足够安全了。