简评:debug 的时候看到 element 对象中有 $$typeof 这属性,于是查了一下这到底干嘛的。

我们知道,通过 JSX 创建一个 React Elements 时:

<marquee bgcolor="#ffa7c4">hi</marquee>

实际上调用的是 React.createElement 方法:

React.createElement(
  /* type */ 'marquee',
  /* props */ { bgcolor: '#ffa7c4' },
  /* children */ 'hi'
)

该方法会返回一个 React Element 对象,大概长这样:

{
  type: 'marquee',
  props: {
    bgcolor: '#ffa7c4',
    children: 'hi',
  },
  key: null,
  ref: null,
  $$typeof: Symbol.for('react.element'), // ? Who dis
}

这个 $$typeof 是什么? 

各种前端框架出现之前,应用通常会构造 HTML 并将它们插入到 DOM 中,例如:

const messageEl = document.getElementById('message');
messageEl.innerHTML = '<p>' + message.text + '</p>';

这代码一般能正常工作,除非你的 message.text 返回 '<img src onerror="stealYourPassword()">' 这样的字符串。

为了防止这种情况,可以使用类似于 document.createTextNode()textContent 仅处理 text 的 api。也可以通过预处理替换 < > 这类特殊的字符。但是这样还是有很多潜在的问题。所以现代前端框架像 React 会为字符串转义成文字内容:

<p>
  {message.text}
</p>

就算 message.text 返回 <img> 也会当成字符串处理。要在 React 元素中呈现 HTML ,则需要编写dangerouslySetInnerHTML={{ __html: message.text }},这有助于你在审查代码的时候重视它。

但是这样仍然无法完全禁止注入攻击,例如:<a href={user.website}>,注意 website 为 'javascript: stealYourPassword()'的情况。 对用户输入使用 ... 运算符也很危险 <div {...userData}>。 

为什么需要 $$typeof

通过上面的介绍你可能已经猜到了,$$typeof 是为了防止 XSS 攻击。

前面介绍了,React 元素大概是这样的(没有包含 $$typeof 这个属性的情况):

{
  type: 'marquee',
  props: {
    bgcolor: '#ffa7c4',
    children: 'hi',
  },
  key: null,
  ref: null
}

试想这样一种情况,服务器允许用户储存任意的 JSON 数据。那么就可以手动构建 React Element 对象传入到元素中。例如:

// Server could have a hole that lets user store JSON
let expectedTextButGotJSON = {
  type: 'div',
  props: {
    dangerouslySetInnerHTML: {
      __html: '/* put your exploit here */'
    },
  },
  // ...
};
let message = { text: expectedTextButGotJSON };

// Dangerous in React 0.13
<p>
  {message.text}
</p>

所以 React 0.14 使用 Symbol 标记每个 React 元素。

{
  type: 'marquee',
  props: {
    bgcolor: '#ffa7c4',
    children: 'hi',
  },
  key: null,
  ref: null,
  $$typeof: Symbol.for('react.element'),
}

这样就可以规避这个问题,使用 Symbol 类型是因为 JSON 中无法传递 Symbol。React 会检查 element.$$typeof 然后拒绝处理非法的元素。

原文: Why Do React Elements Have a $$typeof Property?

极光JIGUANG
1.3k 声望1.3k 粉丝

极光(www.jiguang.cn)是中国领先的移动大数据服务商。其团队核心成员来自腾讯、摩根士丹利、豆瓣、Teradata和中国移动等公司。公司自2011年成立以来专注于为app开发者提供稳定高效的消息推送、统计分析、即时通...