如何在react中安全地呈现 html?

IT技术 html reactjs
2021-04-21 17:27:10

我有一些用户从文本区域生成的 html 标记,我想在屏幕的另一部分呈现它。标记以字符串形式保存在组件的 props 中。

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

3个回答

消毒使用的HTML的sanitize-HTMLmodule,并呈现使用消毒串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以下内容的react包装器

<SanitizedHTML
  allowedAttributes={{ 'a': ['href'] }}
  allowedTags={['a']}
  html={ `<a href="http://bing.com/">Bing</a>` }
/>
好的,因为需要为单独的两个包安装... react-sanitized-html 和 sanitize-html :/
2021-05-24 17:27:10
这是一个与构建相关的问题。你应该打开一个新问题。
2021-06-11 17:27:10
您好@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
2021-06-12 17:27:10
我不明白react-sanitized-html@2.0.02kb 如果是 的包装器sanitize-html,什么时候sanitize-html@1.20.0是 157.2kB :/!
2021-06-19 17:27:10
因为 sanitize-html 是对等依赖项,而不是包的实际部分。
2021-06-20 17:27:10

基于已接受答案的示例:

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>

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

以下是https://stackoverflow.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-dompurifymodule,该module在前端和后端统一使用 DOMPurify。

这似乎是一个更好的选择,因为它提供了所需要的@15kB bundlephobia.com/result?p=dompurify@2.1.1
2021-05-31 17:27:10