安全问题

控制元素类型

createElement函数在type参数中接受一个字符串。如果字符串由用户控制,就可以创建任意React组件:

// 从存储在后端的字符串动态创建元素
// stored_value是用户控制的字符串
element_name = stored_value;
React.createElement(element_name, null);

然而,这只会生成一个普通的、无属性的HTML元素(相当无用)。

注入props

createElement函数在props参数中接受一个属性列表。如果列表由用户控制,就可以向新元素注入任意props:

// 解析用户提供的JSON并将结果对象作为props传递
// stored_value是带有属性的用户控制JSON字符串
props = JSON.parse(stored_value);
React.createElement("span", props);

您可以使用以下payload来设置dangerouslySetInnerHTML属性:

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

显式设置dangerouslySetInnerHTML

如果用户提供的数据用于设置dangerouslySetInnerHTML属性,您可以插入任意JavaScript代码:

<div dangerouslySetInnerHTML={user_supplied} />

显式设置href

如果用户提供的数据用于设置href属性,您可以插入javascript: URL:

<a href={user_supplied}>Link</a>

其他一些属性如HTML5按钮中的formaction或HTML5 imports也可能存在漏洞:

// HTML5按钮
<button form="name" formaction={user_supplied}/>
// HTML5 import
<link rel="import" href={user_supplied}>

滥用服务器端渲染

如果用户控制的数据传递给依赖用户生成内容和输入的代码而没有适当的净化,您可以注入任意JavaScript代码。

例如,官方的Redux SSR代码示例存在XSS漏洞(该示例已修复):

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>
  `
}

在上面的示例中,JSON.stringify函数的结果被赋值给<script>标签中的全局变量,这就是漏洞所在。如果Redux存储具有以下值:

{
    user: {
        username: "username",
        bio: "bio</script><script>alert(1)</script>"
    }
}

当浏览器解析页面并遇到该<script>标签时,它将继续读取直到</script>。浏览器不会读取到最后一个大括号,相反,它实际上会在bio: "as之后结束脚本标签。

参考:

参考

最后更新于