为什么React元素有一个$$typeof属性?

栏目: IOS · Android · 发布时间: 5年前

内容简介:你觉得你在写JSX:其实,你在调用一个方法:之后方法会返回一个对象给你,我们称此对象为React的

你觉得你在写JSX:

<marquee bgcolor="#ffa7c4">hi</marquee>
复制代码

其实,你在调用一个方法:

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

之后方法会返回一个对象给你,我们称此对象为React的 元素 (element),它告诉React下一个要渲染什么。你的组件(component)返回一个它们组成的树(tree)。

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

如果你用过React,对 typepropskey 、 和 ref 应该熟悉。 $$typeof 是什么?为什么用 Symbol() 作为它的值

这又是一个与你学习使用React不 相关 的点,但了解后你会觉得舒坦。这篇文章里也提到了些关于安全的提示,你可能会感兴趣。也许有一天你会有自己的UI库,这些都会派上用场的,我真的希望如此。

在客户端UI库变得普遍且具有基本保护作用之前,应用程序代码通常是先构建 HTML,然后把它插入DOM中:

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

这样看起来没什么问题,但当你 message.text 的值类似 '<img src onerror="stealYourPassword()">' 时, 你不会希望别人写的内容在你应用的HTML中逐字显示的。

(有趣的是:如果你只是在前端渲染,这里为 <script> 标签,JavaScript代码不会被运行。但不要因此让你陷入已经安全的错觉。)

为什么防止此类攻击,你可以用只处理文本的 document.createTextNode() 或者 textContent 等安全的API。你也可以事先将用户输入的内容,用转义符把潜在危险字符( <> 等)替换掉。

尽管如此,这个问题的成本代价很高,且很难做到用户每次输入都记得转换一次。 因此像React等新库会默认进行文本转义:

<p>
  {message.text}
</p>
复制代码

如果 message.text 是一个带有 <img> 或其他标签的恶意字符串,它不会被当成真的 <img> 标签处理,React会先进行转义 然后 插入DOM里。所以 <img> 标签会以文本的形式展现出来。

要在React元素中渲染任意HTML,你不得不写 dangerouslySetInnerHTML={{ __html: message.text }}其实这种愚蠢的写法是一个功能 ,在code reviews和代码库审核时,你可以非常清晰的定位到代码。

这意味着React完全不惧注入攻击了吗?不,HTML和DOM暴露了 大量攻击点 ,对React或者其他UI库来说,要减轻伤害太难或进展缓慢。大部分存在的攻击方向涉及到属性,例如,如果你渲染 <a href={user.website} ,要提防用户的网址是 'javascript: stealYourPassword()' 。 像 <div {...userData}> 写法几乎不受用户输入影响,但也有危险。

React 可以 逐步提供更多保护,但在很多情况下,威胁是服务器产生的,这不管怎样都 应该 要避免。

不过,转义文本这第一道防线可以拦下许多潜在攻击,知道这样的代码是安全的就够了吗?

// Escaped automatically
<p>
  {message.text}
</p>
复制代码

好吧,也不总是有效的。这就是 $$typeof 的用武之地了。

React元素(elements)是设计好的 plain object

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

虽然通常用 React.createElement() 创建它,但这不是必须的。有一些React用例来证实像上面这样的 plain object 元素是有效的。当然,你不会 这样写的,但这 可以用来 优化编译器,在 workers 之间传递UI元素,或者将JSX从React包解耦出来。

但是,如果你的服务器有允许用户存储任意JSON对象的漏洞,而前端需要一个字符串,这可能会发生一个问题:

// 服务端允许用户存储JSON
let expectedTextButGotJSON = {
  type: 'div',
  props: {
    dangerouslySetInnerHTML: {
      __html: '/* 把你想的搁着 */'
    },
  },
  // ...
};
let message = { text: expectedTextButGotJSON };

// Dangerous in React 0.13
<p>
  {message.text}
</p>
复制代码

在这个例子中,React 0.13很容易受到XSS攻击。再次声明, 这个攻击是服务端存在漏洞导致的 。不过,React会为了大家的安全做更多工作。从React 0.14开始,它做到了。

React 0.14修复手段是用Symbol标记每个React元素(element):

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

这是个有效的办法,因为JSON不支持 Symbol 类型。 所以即使服务器存在用JSON作为文本返回安全漏洞,JSON里也不包含 Symbol.for('react.element') 。React会检测 element.$$typeof ,如果元素丢失或者无效,会拒绝处理该元素。

特意用 Symbol.for() 的好处是 Symbols 通用于 iframes 和 workers 等环境中 。因此无论在多奇怪的条件下,这方案也不会影响到应用不同部分传递可信的元素。同样,即使页面上有很多个React副本,它们也 “接受” 有效的 $$typeof 值。

如果浏览器不支持Symbols 怎么办?

唉,那这种保护方案就无效了。React仍然会加上 $$typeof 字段以保证一致性,但只是 设置一个数字 而已—— 0xeac7

为什么是这个数字?因为 0xeac7 看起来有点像 “React”。

翻译原文 Why Do React Elements Have a $$typeof Property? (2018-12-03)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Powerful

Powerful

Patty McCord / Missionday / 2018-1-25

Named by The Washington Post as one of the 11 Leadership Books to Read in 2018 When it comes to recruiting, motivating, and creating great teams, Patty McCord says most companies have it all wrong. Mc......一起来看看 《Powerful》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具