如何在反应中安全地呈现html?

Posted

技术标签:

【中文标题】如何在反应中安全地呈现html?【英文标题】:How to safely render html in react? 【发布时间】:2016-12-04 11:05:38 【问题描述】:

我从文本区域获得了一些用户生成的 html 标记,我想将它呈现在屏幕的另一部分。标记作为字符串保存在组件的 props 中。

出于明显的原因,我不想使用危险的sethtml。是否有诸如 marked 之类的解析器,但用于 html,以便它去除脚本标签和其他无效的 html。

【问题讨论】:

【参考方案1】:

对于 XSS 过滤,安全人员编写的 sanitize-html 有一个很好的替代方案,称为 dompurify。

以下是来自https://***.com/a/38663813/1762849 的包装器在使用 DOMPurify 时的外观:

const defaultOptions = 
  ALLOWED_TAGS: [ 'b', 'i', 'em', 'strong', 'a' ], 
  ALLOWED_ATTR: ['href']
;

const sanitize = (dirty, options) => (
  __html: DOMPurify.sanitize(
    dirty, 
     ...defaultOptions, ...options 
  )
);

const SanitizeHTML = ( html, options ) => (
  <div dangerouslySetInnerHTML=sanitize(html, options) />
);

用法:

<SanitizeHTML html="<img src=x onerror=alert('img') />" />

另外,如果您需要清理客户端和服务器上的 HTML,请考虑使用 isomophic-dompurify 模块,该模块在前端和后端统一使用 DOMPurify。

【讨论】:

这似乎是一个更好的选择,因为它提供了所需要的 @15kB bundlephobia.com/result?p=dompurify@2.1.1【参考方案2】:

使用 sanitize-html 模块清理 html,并使用 dangerouslySetInnerHTML 呈现清理后的字符串。

您可以创建一个简单的包装组件:

const defaultOptions = 
  allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ],
  allowedAttributes: 
    'a': [ 'href' ]
  ,
  allowedIframeHostnames: ['www.youtube.com']
;

const sanitize = (dirty, options) => (
  __html: sanitizeHtml(
    dirty, 
    options:  ...defaultOptions, ...options 
  )
);

const SanitizeHTML = ( html, options ) => (
  <div dangerouslySetInnerHTML=sanitize(html, options) />
);

用法:

<SanitizeHTML html="<img src=x onerror=alert('img') />" />

您还可以使用react-sanitized-html 的 SanitizedHTML 组件,它是sanitize-html 周围的反应包装器:

<SanitizedHTML
  allowedAttributes= 'a': ['href'] 
  allowedTags=['a']
  html= `<a href="http://bing.com/">Bing</a>` 
/>

【讨论】:

我不明白react-sanitized-html@2.0.0sanitize-html 的一个包装器,而sanitize-html@1.20.0 是157.2kB 时只有2kb:/! 好的,因为需要分别安装两个包... react-sanitized-html 和 sanitize-html :/ 因为 sanitize-html 是对等依赖项,而不是包的实际部分。 您好@ori,我正在按照您的指示进行操作,但我的编译器出现错误[11:40:00] Starting 'browserify_typescript'... [11:40:04] 'browserify_typescript' errored after 4.29 s [11:40:04] Error in plugin 'gulp-browserify' module "./tagtypes" not found from "/d/myProject/web/node_modules/sanitize-html/dist/sanitize-html.js" 它说./tagtypes not found 这是与构建相关的问题。您应该提出一个新问题。【参考方案3】:

基于已接受答案的示例:

import sanitizeHtml from 'sanitize-html';

const MyComponent = () => 
  dirty = '<a href="my-slug" target="_blank" onClick="evil()">click</a>';
  const clean = sanitizeHtml(dirty, 
    allowedTags: ['b', 'i', 'em', 'strong', 'a'],
    allowedAttributes: 
      a: ['href', 'target']
    
  );
  return (
    <div 
      dangerouslySetInnerHTML=__html: clean
    />
  );
;

MyComponent 呈现 div 包含不带 onClick="evil()" 的链接:

<a href="my-slug" target="_blank">click</a>

【讨论】:

以上是关于如何在反应中安全地呈现html?的主要内容,如果未能解决你的问题,请参考以下文章

如何在本机反应中呈现html音频标签?

如何在 Windows 窗体中呈现化学反应? [关闭]

如何在 ReactJS 中呈现静态 html 页面?

如何使 HTML 面向列和基于 div 的表格的高度在反应中相同

在 Django 模板中的 JSON 中安全地使用带有 html 的 JSON

如何做一些项目或标题不应该在本机反应中多次呈现