dangerouslySetInnerHTML 的安全替代品

Safe alternative to dangerouslySetInnerHTML

我想在我的网站上有一个动态博客(使用 React)。最初,我打算将 posts 存储在我的数据库中的原始 HTML 中,并使用 dangerouslySetInnerHTML 生成内容。但是,我担心安全隐患。虽然我的应用程序没有任何敏感数据,但我对 XSS 不够精通,无法了解打开我的应用程序可能面临的所有危险。

我很好奇是否有一种高效、安全的方法可以在我的应用程序中动态加载博客页面。在这种情况下使用 https://github.com/odysseyscience/react-router-proxy-loader 会有用吗?将 blog post JSX 文件夹与我的应用程序的其余部分分开,并使用它加载它(诚然,我不确定 react-router-proxy-loader 是如何工作的)。

我乐于接受建议。

如果 XSS 是您最关心的问题,您可以使用 DOMPurify to sanitize your HTML before inserting it in the DOM via dangerouslySetInnerHTML. It's just 10K minified. And it works in Node too.

https://facebook.github.io/react/tips/dangerously-set-inner-html.html

"The prop name dangerouslySetInnerHTML is intentionally chosen to be frightening. ..."

"After fully understanding the security ramifications and properly sanitizing the data..."

我想,如果你相信你自己的 CMS/Server(而不是从第 3 方接收),它已经清理了数据(这一步也完成了),那么你可以使用 dangerouslySetInnerHTML.

正如 Morhaus 所说,也许使用 DOMPurify 因为它(奖金)可能会处理这个不幸的位:"so the HTML provided must be well-formed (ie., pass XML validation)." 我怀疑某些内容使用 [=27 的非 XML 版本=] 否则可能是一个问题。 (注意:我自己还没有用过,因为我和你一样是新手。)

如果您 确定 输入 HTML 是安全的(没有 XSS 风险)但可能格式不正确(例如文本中有一个随机的 < ),并且您想防止您的应用程序因意外的 DOM 更改而失败,那么您可以试试这个:

function sanitize(html) {
  var doc = document.createElement('div');
  doc.innerHTML = html;
  return doc.innerHTML;
}

(基于)

但如果您对您的 HTML 可能是 not-XSS-safe 有丝毫怀疑,请使用上述 DOM 净化。

我遇到了同样的问题,但最终得到了更好的解决方案。如果您输入类似下面的内容,并且解决方案将适用于您使用 lodash

&lt;em&gt;paragraph text example:&lt;/em&gt;

我的解决方案:

import _ from 'lodash';

const createMarkup = encodedHtml => ({
  __html: _.unescape(encodedHtml),
});

/* eslint-disable react/no-danger */
const Notes = ({ label }) => (
  <div>
    <div dangerouslySetInnerHTML={createMarkup(label)} />
  </div>
);

文章 How to prevent XSS attacks when using dangerouslySetInnerHTML in React 建议使用 jam3/no-sanitizer-with-danger eslint 规则来检查传递给 dangerouslySetInnerHTML 的内容是否包含在此清理函数中

有效代码示例为

const sanitizer = dompurify.sanitize;
return <div dangerouslySetInnerHTML={{__html: sanitizer(title)}} />; // Good

它还描述了 3 个消毒剂库:
DOMPurify
Xss.
xss-filters

如其他答案所述,许多库(dompurify, xss 等)可以解析您提供给浏览器的 HTML,删除任何恶意部分并安全地显示它。

问题是:如何强制使用这些库。

为此,您可以安装 RisXSS,这是一个 ESLint 插件,它会警告 dangerouslySetInnerHTML 如果 您之前没有对其进行清理(从某种意义上说,这是 react/no-danger ESLint 规则的改进版本)。

为此,安装 dompurifyeslint-plugin-risxss:

npm install dompurify eslint-plugin-risxss

risxss 添加到您的 ESLint 插件,然后使用 DOMPurify:

import { sanitize } from 'dompurify';

export const MyArticle = ({ post }) => (
  <>
    <div dangerouslySetInnerHTML={{ post.content }} /> {/* You will receive a warning */}
    <div dangerouslySetInnerHTML={{ __html: sanitize(post.content) }} /> {/* All good here */}
  </>
);

免责声明:我是 RisXSS 插件的贡献者。

使用 React 库 Interweave.

  1. 安全地渲染 HTML 而不使用 dangerouslySetInnerHTML。
  2. 安全剥离 HTML 个标签。
  3. 自动 XSS 和注入保护。
  4. 使用过滤器清除 HTML 属性。
  5. 使用匹配器插入组件。
  6. 自动链接 URL、IP、电子邮件和主题标签。
  7. 渲染 Emoji 和图释字符。

https://www.npmjs.com/package/interweave

Safe alternative to dangerouslySetInnerHTML

I'm curious if there's a performant, safe way to dynamically load blog pages within my app

有趣的是,虽然问题是 dangerouselySetInnerHTML 的替代方法,但所有答案都指示无论如何都要使用它。这是否意味着您别无选择?不,只是不容易。

备选方案 1:改写您的应用以将数据传递给组件

Initially, I was going to store the posts in raw HTML

从回答来看似乎没有这样的要求。它可以作为一个简单的解决方案来实现,不用担心与您的组件匹配的数据模式。但这不太可能是硬性要求。

您的应用程序 re-architect 应该可以不依赖于存储原始数据 HTML,尽管这可能意味着很多工作,具体取决于应用程序。

备选方案 2:不要编写自己的页面构建器

如果您只是想在自己的网站上创建一个博客,那么编写自己的页面构建器可能不值得。即使您想与网站的其他部分紧密集成,如果您使用 WordPress 之类的东西,那仍然是可能的。

备选方案 3(仅限 WordPress):使用 InnerBlocks

如果您当前在 WordPress 区块中使用 dangerouselySetInnerHTML,您可以将其转换为使用 InnerBlocks