美文网首页互联网科技
为什么 React Elements 会有 $$typeof 这

为什么 React Elements 会有 $$typeof 这

作者: 极小光 | 来源:发表于2019-01-03 14:33 被阅读21次

    简评: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?
    推荐阅读:作为软件工程师,如何进行知识管理

    相关文章

      网友评论

        本文标题:为什么 React Elements 会有 $$typeof 这

        本文链接:https://www.haomeiwen.com/subject/omwxlqtx.html