内容简介:你觉得你在写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,对 type
、 props
、 key
、 和 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)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- WPF 元素裁剪 Clip 属性
- PHP的SimpleXML遍历所有子元素及访问特定节点元素和属性
- jscript与vbscript 操作XML元素属性的代码
- [译] 我在阅读 MDN 时发现的 3 个 Input 元素属性
- WPF 中使用附加属性,将任意 UI 元素或控件裁剪成圆形(椭圆)
- javascript – 如何使用jquery查找包含与前缀匹配的data- *属性的元素
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
离散数学及其应用(原书第4版)
Kenneth H.Rosen / 机械工业出版社 / 2002-1-1 / 75.00
离散数学及其应用:原书第4版,ISBN:9787111075776,作者:(美)Kenneth H.Rosen著;袁崇义[等]译一起来看看 《离散数学及其应用(原书第4版)》 这本书的介绍吧!