React 最重要也最容易被遗忘的属性 $$typeof

更新日期: 2020-02-05 阅读: 2.5k 标签: 属性
为什么说 $$typeof 是最重要的属性?因为它是代码安全的一道重要防线。

如果你用过 react,对 type、 props、 key、 和 ref 应该熟悉。 但你不一定知道 $$typeof


首先简单介绍下JSX

当你在写 JSX 时,其实你在调用createElement方法。

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

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

{
  type: 'marquee',
  props: { //... },
  key: null,
  ref: null,
  $$typeof: Symbol.for('react.element'),
}


html的插入转义

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

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

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

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

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

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

在 React 中如果元素要渲染 HTML,那么需要使用 dangerouslySetInnerHTML={{ __html: message.text }}

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

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


关于 $$typeof

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

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

// React 0.13 中有风险
<p>
  {message.text}
</p>

在这个例子中,React 0.13 很容易受到 XSS 攻击。虽然 这个攻击是服务端存在漏洞导致的。不过,从 React 0.14 开始,这个问题修复了。

React 0.14 修复手段是在虚拟DOM中添加 $$typeof,使用 Symbol 标记每个 React 元素(element):

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

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

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


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/7948

相关推荐

html中的marquee属性

该标签不是HTML3.2的一部分,并且只支持MSIE3以后内核,所以如果你使用非IE内核浏览器(如:Netscape)可能无法看到下面一些很有意思的效果,该标签是个容器标签

vue里的$refs属性

vuejs的极大程度的帮助减少了对dom的操作,他主要通过添加ref属性,但是当获取this.$refs属性时,稍有不注意就会输出undefined导致我们对dom节点的操作报错。this.$refs.xxx为undefined的几种情况记录:

css的overflow属性

事实上我挺长一段时间都没弄清楚overflow:scroll与overflow:auto的差别,今天测试了一下,总算是明白了。visible: 不剪切内容。hidden: 将超出对象尺寸的内容进行裁剪,将不出现滚动条。scroll: 将超出对象尺寸的内容进行裁剪,并以滚动条的方式显示超出的内容。

css使用到的border边框属性

border 在一个声明中设置所有的边框属性。 border-bottom在一个声明中设置所有的下边框属性。border-bottom-color设置下边框的颜色。border-bottom-style设置下边框的样式。

Cookie 的 SameSite 属性

Chrome 51 开始,浏览器的 Cookie 新增加了一个 SameSite 属性,用来防止 CSRF 攻击和用户追踪。Cookie 往往用来存储用户的身份信息,恶意网站可以设法伪造带有正确 Cookie 的 HTTP 请求,这就是 CSRF 攻击。

React 也能“用上” computed属性

初次见到计算属性一词,是在 Vue 官方文档 《计算属性和侦听器》 一节中,文章中是这样描述计算属性的:模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。

css常用属性

text-align 属性规定元素中的文本的水平对齐方式。属性值:none | center | left | right | justify;font-size表示设置字体大小,如果设置成inherit表示继承父元素的字体大小值。

JS、Jquery中判断checkbox是否选中

attr()与prop()如何选择:attr()方法返回被选元素的属性值。prop() 方法设置或返回被选元素的属性和值。当该方法用于返回属性值时,则返回第一个匹配元素的值。当该方法用于设置属性值时,则为匹配元素集合设置一个或多个属性/值对。

css z-index属性

z-index 仅适用于定位元素。即 postition 值为 relative, absolute 和 fixed 属性;堆叠顺序是当前元素位于 z 轴上的值。值越大表示元素越靠近屏幕,反之元素越远离屏幕在同一个堆叠上下文中, z-index 值越大,越靠近屏幕。

CSS中的cursor属性

css中的cursor这个属性是用来设置光标形状的。这个属性定义了鼠标指针放在一个元素边界范围内时所用的光标的形状。默认值:auto,继承性:yes,出现版本:css2

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!