这篇文章的作者(我们今天将要翻译的译本)说,React是她最喜欢的用于创建交互式界面的库。 React易于使用,并且受到了很好的保护。 但是,这并不意味着React应用程序是完全无害的。 决定不必担心XSS攻击是很容易陷入无理的平静之中,因为该项目使用了React。
当开发人员认为他正在使用该库的保护机制时,React中的漏洞通常会发生,尽管实际上事实并非如此。 因此,正确评估React的功能并知道程序员需要自己完成哪些任务非常重要。

今天,我们将讨论典型的React漏洞,如何在代码审查期间找到它们以及如何防御它们。
第一个(非常简短)的跨站点脚本编写示例
跨站点脚本(XSS)是一个客户端漏洞,可能导致严重问题。 当攻击者能够诱骗网站并强迫其在其用户的浏览器中执行任意JavaScript代码时,就会发生XSS攻击。
反射的XSS攻击是通过包含文本信息的链接进行的,该链接由浏览器以代码形式处理。 例如,这是一个表单字段,其中在客户端输入了特殊的请求文本。
存储的XSS攻击是指攻击者可以访问服务器,并且在服务器上执行的代码生成可到达客户端网页的内容的情况。 这种攻击的典型载体是将评论和图像上传到服务器。
Samy蠕虫利用了MySSpace XSS漏洞。 它是有史以来传播速度最快的病毒之一。
易受攻击的网站可能使他们的用户遭受密码或个人数据的盗窃。 这是利用其他漏洞的常用方法。 恶意脚本最常用于发送垃圾邮件并将用户重定向到欺诈站点。 这可能会损害成功攻击的网站的声誉和SEO性能。
漏洞#1:控制页面的初始状态,该状态在服务器渲染期间使用
有时,当我们形成页面的初始状态时,很危险,我们会基于JSON字符串创建文档。 代码中的此漏洞如下所示:
<script>window.__STATE__ = ${JSON.stringify({ data })}</script>
这很危险,因为
JSON.stringify()
方法没有任何“思考”,而是将以字符串形式(只要它是有效的JSON数据)转换提供给它的任何数据转换为将显示在页面上。 如果
{ data }
具有不受信任的用户可以编辑的字段,例如用户名或用户信息,则可以在此类字段中嵌入以下内容:
{ username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }
此模式通常用于使用Redux的React应用程序的服务器端渲染中。 他出现在Redux官方文档中,因此,仍然可以在GitHub上找到许多教程和示例应用程序模板。
不信? 然后自己看看。 在Google上搜索“反应服务器端渲染示例应用程序”文本,然后对第一页中的任何搜索结果进行此攻击。
code在代码审查期间确定漏洞
查找对
JSON.stringify()
方法的调用,该方法接受在
script
标记中可能包含不可信数据的变量。 这是Redux文档中曾经存在的示例:
function renderFullPage(html, preloadedState) { return ` <!doctype html> <html> <head> <title>Redux Universal Example</title> </head> <body> <div id="root">${html}</div> <script> window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)} </script> <script src="/static/bundle.js"></script> </body> </html> ` }
这是在GitHub上找到的示例应用程序的一段代码:
function htmlTemplate( reactDom, reduxState, helmetData ) { return ` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ${ helmetData.title.toString( ) } ${ helmetData.meta.toString( ) } <title>React SSR</title> <link rel="stylesheet" type="text/css" href="./styles.css" /> </head> <body> <div id="app">${ reactDom }</div> <script> window.REDUX_DATA = ${ JSON.stringify( reduxState ) } </script> <script src="./app.bundle.js"></script> </body> </html> `; }
有时发现此漏洞要困难一些。 如果未正确转义
context.data
以下代码也将是不安全的:
const RenderedApp = htmlData.replace('{{SSR}}', markup) .replace('<meta-head/>', headMarkup) .replace('{{data}}', new ArrayBuffer(JSON.stringify(context.data)).toString('base64'))
在进行服务器端渲染时,请注意要渲染的内容。 如果用户输入的内容未正确屏蔽并在DOM中显示,则可能很危险。
▍保护
防范此漏洞的一种方法是使用
serialize-javascript
npm模块,该模块旨在屏蔽输出JSON。 如果要在非Node.js环境中进行服务器渲染,则需要为您的语言选择适当的包。
这是安装模块的命令:
$ npm install --save serialize-javascript
之后,您需要将其导入文件并重写以前易受攻击的处理
window
代码
window
如下所示:
<script>window.__STATE__ = ${ serialize( data, { isJSON: true } ) }</script>
这是一篇关于这个主题
的好文章。
漏洞№2:阴险链接
<a>
标记可以具有
href
属性,该属性包含指向该站点的另一个页面,另一个站点以及当前页面上某个位置的链接。 链接可能包含如下所示的脚本:
javascript: stuff()
。 如果您不知道此HTML功能,请立即将以下代码复制到浏览器行中,以进行尝试:
data:text/html, <a href="javascript: alert('hello from javascript!')" >click me</a>
对于Web开发人员,这意味着,如果链接的内容是根据用户输入的数据设置的,则攻击者可以向该数据添加以
javascript:
开头的恶意代码。 然后,如果用户单击错误的链接,则会在浏览器中启动攻击者脚本。
这个漏洞绝对不仅是React的特征,而且是React开发人员在期望正确地自动转义相应值时经常遇到的问题之一。 应当指出,在React的
未来版本中,此问题将不太严重。
code在代码审查期间确定漏洞
项目用户能否将链接添加到其他用户可以单击的页面? 如果是这样,请尝试向页面添加“链接”,如下所示:
javascript: alert("You are vulnerable to XSS!")
如果通过单击链接显示相应的消息框,则表明该项目容易受到XSS攻击。 在可以添加链接的任何地方尝试此操作。 并非所有这些地方都容易受到伤害。
▍保护
防范此漏洞不仅适用于React项目。 确切需要执行的操作取决于应用程序。 此外,您可能需要在服务器上进行更正。
您可能会认为,要解决该问题,只需从数据中删除
javascript:
前缀即可。 这是使用黑名单策略的一个示例,无法成功
清除数据 。 黑客们有巧妙的方法绕过此类过滤器,因此,使链接使用列入白名单的协议(例如,
http:
逃避HTML实体,而不是采取这种措施(或除此以外)。
这是有关此主题
的详细文章,内容涉及保护攻击者可以控制的属性。
可以为项目添加额外保护级别的另一种策略是使用该机制在新的浏览器选项卡中打开自定义链接。 但是,我不建议将此策略用作项目的唯一“防线”。 打开
javascript:
新标签中的链接是页面元素的非标准行为的示例。 大多数浏览器将在一个空白选项卡中运行该脚本而不损害用户,但这不能保证,您可能可以解决此问题,具体取决于浏览器。
考虑使用特殊的
UserLink组件,这将导致以下事实:易受攻击的
<a>
标记将来不太可能到达您项目的页面。 此外,值得在项目中添加一些测试和整理规则,以识别潜在的危险代码并阻止其投入生产。
链接不是唯一可以这种方式使用的实体。 但是它们是React应用程序中最有可能的攻击目标。 如果攻击者可以控制其
URI
值,则任何元素都可能容易受到此攻击。 进行这种攻击的另一种可能性是例如视图设计。 可以使用浏览器搜索(
Ctrl+F
)使用关键字
%URI
在
此列表中找到可能包含URI的属性的完整列表。
漏洞#3:误解构造的含义危险SetInnerHtml
我非常感谢React安全警告直接在方法名称中。 这是
dangerouslySetInnerHTML
的名称
dangerouslySetInnerHTML
。 尽管有此警告,但我们仍然经常面临这样的事实,即开发人员通过执行不安全的操作来冒险。
eval()
也可以这样说。
考虑以下示例,该示例是我在Google搜索结果首页上的网站上找到的:
<script dangerouslySetInnerHTML={{ __html: `window.__PRELOADED_STATE__ = ${JSON.stringify(initialState)};`}}></script>
这是漏洞1的示例,但是具有一个功能,该功能应立即引起人们对这里出了问题的事实的关注。 在发现该错误的地方,我们试图做出解释:“我们将
危险地使用
SetInnerHTML作为清除数据和防止XSS攻击的方法。” 好吧,不! 错了 不要这样做。 有关dragonallySetInnerHTML的更多信息,请阅读React文档。
这实际上一直发生的另一个示例是,同一团队的成员如何使用
dangerouslySetInnerHTML
SetInnerHTML向页面添加Markdown标记时发现他们存在
漏洞 。 为了将来保护自己免受这种情况的侵害,他们开始使用特殊的掉毛规则。
code在代码审查期间确定漏洞
在发送拉取请求或执行合并操作之前,在代码中搜索
dangerouslySetInnerHTML
和
eval
字符串(我也以此方式查找
console.log
命令)或使用相应的linter规则非常有用。
▍保护
确保在所有使用
dangerouslySetInnerHTML
方法的情况下,仅将您可以信任的数据加载到页面上。 您如何知道数据是否可以信任? 如果您没有收到任何东西,可能会构成威胁。 这包括从外部API下载的数据以及使用Markdown工具发布的数据。
组件欺骗注意
在2015年,
有人发现您可以通过将JSON传递给需要文本的那些组件来欺骗组件。 我仅能找到一种情况,其中有一个组件欺骗消息,以及由该消息引起的
长时间讨论 。 讨论重点是React负责防止XSS攻击的原因。 结果,React开发人员发布了一个
修复程序 ,该
修复程序似乎有助于修复此漏洞。
我决定不在文章中包含有关此漏洞的故事,但是可能需要对该主题进行进一步的研究。
SSR说明
服务器呈现漏洞之所以如此普遍,是因为该事实存在于Redux文档中,结果分散在许多其他材料中。 该问题已在2016年修复。 但是即使到了三年后的今天,散布在互联网上的新手指南仍然会教您不应该教的内容。
顺便说一下,这是您的作业:在GitHub上找到此问题的示例,并发送请求请求进行修复。
这是一个例子 。
我们在一起可以一劳永逸地摆脱这个漏洞!
亲爱的读者们! 您是否在React项目上遇到过攻击?
