在 SXSS 漏洞被利用之前识别并缓解它们
卢克·哈里森
本文最初发布在 IBM Developer 上。
当前许多应用程序需要在其网站上呈现 HTML 格式的富文本。为了根据用户输入生成这种格式化文本,开发人员使用富文本编辑器组件。问题?此功能可以间接使您的应用程序和数据面临称为存储跨站点脚本 (SXSS) 的漏洞。
在本文中,您将了解什么是 SXSS 漏洞,并回顾一些可用于检查您的应用程序是否受到影响的“代码味道”。您还将看到易受攻击的应用程序的示例,并了解此漏洞的修复策略。
存储的跨站点脚本是一种漏洞,攻击者可以利用它向数据库注入恶意代码。该代码在由前端框架获取并呈现后,在受害者的浏览器上运行。
此漏洞极其危险,因为它可以使攻击者窃取 cookie、触发重定向或在受害者的浏览器中运行各种危险脚本。攻击者只需很少的工作就可以传播漏洞:受害者不需要点击恶意链接或陷入网络钓鱼计划,他们只需使用受 SXSS 影响的可信站点即可。查看页面底部的链接,了解有关跨站脚本漏洞的更多详细信息。
代码异味只是代码中指示更深层次问题的特征。浏览器通常不会自动运行注入的脚本,但如果开发人员使用一些潜在危险的浏览器 API 或元素属性,则可能会导致脚本 do 运行的情况。
看看下面的代码片段:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
在此示例中,我们将一些 HTML 存储在变量中,从 DOM 中获取元素,并将该元素的 innerHTML 属性设置为存储在变量中的内容。 innerHTML 属性可用于从另一个 HTML 元素内的字符串呈现 HTML。
此属性的危险在于它会渲染您传递给它的任何 HTML 或 JavaScript。这意味着如果有人能够控制传递到属性中的数据,从技术上讲他们就可以在用户的浏览器中运行任何 JavaScript。
在浏览器中渲染动态 HTML 的另一种流行但危险的方法是使用危险的SetInnerHTML React 组件属性。此属性的行为方式与普通 JavaScript 和 HTML 中的innerHTML 属性完全相同。
以下示例出现在 React 文档中:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
如果您当前在前端 Web 应用程序中使用这些属性中的任何一个,那么您很可能存在某种类型的跨站点脚本漏洞。我们将在本文后面介绍如何利用这些属性以及您可以采取的一些步骤来修复这些问题。
您的应用程序可能容易受到 SXSS 攻击的另一个迹象是您是否使用富文本编辑器,例如 TinyMCE 或 CKEditor。
大多数富文本编辑器的工作原理是将用户生成的格式化文本转换为 HTML。作为一项附加的安全措施,许多编辑器采用某种形式的清理来从其输入中删除潜在的恶意 JavaScript。但是,如果您没有在接收和存储富文本内容的服务上应用这些相同的清理技术,那么您的应用程序很可能容易受到 SXSS 的攻击。
即使您没有在自己的网站上渲染内容,这些数据也很有可能被执行渲染的应用程序消耗。要设计安全的应用程序,考虑数据当前和未来的消费者非常重要。如果您的数据受到 SXSS 的影响,那么所有消耗您数据的应用程序也会受到影响。
让我们看一个带有 SXSS 漏洞的 Web 应用程序的小示例,然后尝试利用它。
要运行此应用程序,请首先克隆此演示应用程序存储库并按照 readme.md 文件中的“运行应用程序”说明进行操作。
运行应用程序并访问 http://localhost:3000/unsanitized.html 后,您应该看到如下所示的页面:
此应用程序只是从用户处获取一些富文本输入,将其存储在 Web 服务器上,然后将其呈现在标记为 Output 的部分中。
在我们利用 SXSS 漏洞之前,请花点时间看一下该应用程序。参考上面提到的代码味道,扫描一下代码,看看是否能发现有问题的部分。尝试在浏览器中打开网络选项卡,并查看当您输入并提交一些富文本时它发送的请求。
在 unsanitzed.html 文件中,您将看到以下函数,名为 renderPostByID:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
仔细看这个函数。您会注意到,我们正在使用前面提到的innerHTML 属性来呈现我们从API 中以HTML 形式获取的一些富文本。
现在我们看到了代码中易受攻击的部分,让我们利用它。我们将绕过富文本编辑器输入并点击将帖子直接保存到 Web 服务器的 API 端点。为此,您可以使用以下 cURL 命令:
function createMarkup() { return {__html: 'First · Second'}; } function MyComponent() { return <div dangerouslySetInnerHTML={createMarkup()} />; }
注意我们在请求中发送的数据负载。这是一些恶意制作的 HTML,其中包含一个图像标记,该图像标记的 onerror 属性设置为某些显示警报对话框的 JavaScript。攻击者将使用这样的技巧来避免实施不当的清理方法,这些方法旨在在将 HTML 元素存储到数据库之前从 HTML 元素中剥离 JavaScript。
运行上面的脚本后,您应该会收到如下所示的帖子 ID:
const renderPostByID = async (id) => { // setting url seach params let newURL = window.location.protocol + "//" + window.location.host + window.location.pathname + `?post=${id}`; window.history.pushState({ path: newURL }, "", newURL); // getting rich text by post id let response = await fetch(`/unsanitized/${id}`, { method: "GET" }); let responseJSON = await response.json(); console.log(responseJSON); // rendering rich text output.innerHTML = responseJSON.richText; };
将此帖子 ID 粘贴到帖子 URL 查询参数中,然后按 Enter.
执行此操作时,您应该会在屏幕上看到一个警报对话框,确认该网站确实容易受到 SXSS 的攻击。
如何预防SXSS
利用 SXSS 漏洞,让我们看看如何修复一个漏洞。为此,您需要在三个不同的位置清理基于 HTML 的富文本:
但请记住,向所有三个位置添加消毒可能会导致性能下降,因此您需要自行决定是否需要这种级别的安全性。至少,您应该在渲染动态 HTML 内容之前清理客户端上的所有数据。
让我们看看如何在易受攻击的应用程序的安全版本中实施清理。由于该应用程序主要使用 JavaScript 编写,因此我们在客户端使用 dompurify 库,在服务器端使用 isomorphic-dompurify 库进行清理。在充当我们的 Web 服务器的 app.js 程序中,您将找到一个带有 GET 和 POST 实现的快速端点 /sanitized:
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
在 POST 实现中,我们首先从请求正文中检索富文本,然后调用 isomorphic-dompurify 库的 sanitize 方法,然后将其存储在数据对象中。类似地,在 GET 实现中,我们在从数据对象检索富文本之后并将其发送给消费者之前对富文本调用相同的方法。
在客户端,我们在 sanitized.html 中设置输出 div 的innerHTML 属性之前再次使用相同的方法。
function createMarkup() { return {__html: 'First · Second'}; } function MyComponent() { return <div dangerouslySetInnerHTML={createMarkup()} />; }
现在您已经了解了我们如何正确清理 HTML 以防止跨站点脚本编写,请返回到此应用程序的原始漏洞并再次运行它,这次使用清理后的端点。您不应再看到弹出的警报对话框,因为我们现在正在使用适当的技术来防止 SXSS 漏洞。
有关完整的 SXSS 指南,包括防止 XSS 的最佳实践和其他技术,请查看 OWASP 跨站脚本备忘单。
在本文中,我们了解了如何通过防止存储的跨站点脚本(一种常见的 Web 应用程序漏洞)来提高应用程序的安全性。您现在应该能够识别自己的应用程序是否容易受到攻击、您需要检查哪些功能以及如何在恶意行为者利用这些漏洞之前进行缓解。
安全对于企业开发者来说至关重要。使用以下资源继续增强您对可能存在的漏洞以及改善安全状况的方法的认识。
以上是您的富文本可能是跨站点脚本漏洞的详细内容。更多信息请关注PHP中文网其他相关文章!