简体   繁体   English

在 React SharePoint WebPart 中,使用“html-react-parser”和使用“dompurify eslint-plugin-risxss”来安全地显示 HTML 之间有什么区别

[英]In React SharePoint WebPart what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely show HTML

I am trying to build a React.js SharePoint modern web part, which have the following capabilities:-我正在尝试构建一个 React.js SharePoint 现代 Web 部件,它具有以下功能:-

  1. Inside the Web Part settings page >> there are 2 fields named as "Who We Are" & "Our Value" which allow the user to enter HTML.在 Web 部件设置页面内 >> 有 2 个名为“我们是谁”和“我们的价值”的字段,它们允许用户输入 HTML。

  2. The web part will render 2 buttons "Who We Are" & "Our Value" >> and when the user clicks on any button >> a Popup will be shown with the entered HTML code in step-1 Web 部件将呈现 2 个按钮“我们是谁”和“我们的价值”>> 并且当用户单击任何按钮时 >> 将显示一个弹出窗口,其中包含在第 1 步中输入的 HTML 代码

Something as follow:-如下:-

在此处输入图片说明

But to be able to render HTML code as Rich-Text inside my Web Part, i have to use the dangerouslySetInnerHTML attribute inside the .tsx file.但是为了能够在我的 Web 部件中将 HTML 代码呈现为富文本,我必须在 .tsx 文件中使用dangerouslySetInnerHTML的SetInnerHTML 属性。 as follow:-如下:-

import * as React from 'react';
import { useId, useBoolean } from '@fluentui/react-hooks';
import {
  getTheme,
  mergeStyleSets,
  FontWeights,
  Modal,
  IIconProps,
  IStackProps,
} from '@fluentui/react';
import { IconButton, IButtonStyles } from '@fluentui/react/lib/Button';
export const MYModal2 = (myprops) => {
  const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
  const [isPopup, setisPopup] = React.useState(true);
  const titleId = useId('title');
  React.useEffect(() => {
      showModal();
  }, [isPopup]);
  function ExitHandler() {
    hideModal();
    setisPopup(current => !current)
    myprops.handler();
  }

  return (
    <div>
      <Modal
        titleAriaId={titleId}
        isOpen={isModalOpen}
        onDismiss={ExitHandler}
        isBlocking={true}
        containerClassName={contentStyles.container}
      >
        <div className={contentStyles.header}>
          <span id={titleId}>Modal Popup</span>
          <IconButton
            styles={iconButtonStyles}
            iconProps={cancelIcon}
            ariaLabel="Close popup modal"
            onClick={ExitHandler}
          />
        </div>
        <div  className={contentStyles.body}>
        <p dangerouslySetInnerHTML={{__html:myprops.OurValue}}>
   </p>

        </div>
      </Modal>

    </div>

  );
};

const cancelIcon: IIconProps = { iconName: 'Cancel' };

const theme = getTheme();
const contentStyles = mergeStyleSets({
  container: {
    display: 'flex',
    flexFlow: 'column nowrap',
    alignItems: 'stretch',
  },
  header: [
    // eslint-disable-next-line deprecation/deprecation
    theme.fonts.xLarge,
    {
      flex: '1 1 auto',
      borderTop: '4px solid ${theme.palette.themePrimary}',
      color: theme.palette.neutralPrimary,
      display: 'flex',
      alignItems: 'center',
      fontWeight: FontWeights.semibold,
      padding: '12px 12px 14px 24px',
    },
  ],
  body: {
    flex: '4 4 auto',
    padding: '0 24px 24px 24px',
    overflowY: 'hidden',
    selectors: {
      p: { margin: '14px 0' },
      'p:first-child': { marginTop: 0 },
      'p:last-child': { marginBottom: 0 },
    },
  },
});
const stackProps: Partial<IStackProps> = {
  horizontal: true,
  tokens: { childrenGap: 40 },
  styles: { root: { marginBottom: 20 } },
};
const iconButtonStyles: Partial<IButtonStyles> = {
  root: {
    color: theme.palette.neutralPrimary,
    marginLeft: 'auto',
    marginTop: '4px',
    marginRight: '2px',
  },
  rootHovered: {
    color: theme.palette.neutralDark,
  },
};

And to secure the dangerouslySetInnerHTML , i did the following steps :-为了保护dangerouslySetInnerHTML我执行了以下步骤:-

1- Inside my Node.Js CMD >> i run this command inside my project directory:- 1- 在我的 Node.Js CMD >> 我在我的项目目录中运行这个命令:-

npm install dompurify eslint-plugin-risxss

2- Then inside my above .tsx i made the following modifications:- 2-然后在我上面的.tsx里面我做了以下修改:-

  • I added this import import { sanitize } from 'dompurify';我添加了这个 import import { sanitize } from 'dompurify';
  • An I replaced this unsafe code <p dangerouslySetInnerHTML={{__html:myprops.OurValue}}></p> with this <div dangerouslySetInnerHTML={{ __html: sanitize(myprops.OurValue) }} />我将这个不安全的代码<p dangerouslySetInnerHTML={{__html:myprops.OurValue}}></p>替换为这个<div dangerouslySetInnerHTML={{ __html: sanitize(myprops.OurValue) }} />

So I have the following question:-所以我有以下问题:-

  1. Now my approach (of using sanitize(myprops.OurValue) will/should securely render HTML as Rich-Text inside the popup since i am using the sanitize function which is part of the dompurify eslint-plugin-risxss . but i read another approach which mentioned that to securely render HTML as Rich-Text inside the popup, we can use the html-react-parser package as follow {parse(myprops.OurValue)} . So what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely render an HTML code as Rich-Text inside the React web part's popup?现在我的方法(使用sanitize(myprops.OurValue)将/应该在弹出窗口中安全地将 HTML 呈现为富文本,因为我使用的是sanitize函数,它是dompurify eslint-plugin-risxss 。但我读了另一种方法提到要在弹出窗口中安全地将 HTML 呈现为富文本,我们可以使用html-react-parser包,如下所示{parse(myprops.OurValue)} 。那么使用 'html-react-parser' & 之间有什么区别?使用“dompurify eslint-plugin-risxss”在 React Web 部件的弹出窗口中安全地将 HTML 代码呈现为富文本?

Here is my Full web part code:-这是我的完整 Web 部件代码:-

inside the MyModalPopupWebPart.ts:-在 MyModalPopupWebPart.ts 中:-

import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
  IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';

import * as strings from 'MyModalPopupWebPartStrings';
import MyModalPopup from './components/MyModalPopup';
import { IMyModalPopupProps } from './components/IMyModalPopupProps';

export interface IMyModalPopupWebPartProps {
  description: string;
  WhoWeAre: string;
  OurValue:string;
}

export default class MyModalPopupWebPart extends BaseClientSideWebPart<IMyModalPopupWebPartProps> {

  public render(): void {
    const element: React.ReactElement<IMyModalPopupProps> = React.createElement(
      MyModalPopup,
      {
        description: this.properties.description,
        WhoWeAre: this.properties.WhoWeAre,
        OurValue: this.properties.OurValue
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected onDispose(): void {
    ReactDom.unmountComponentAtNode(this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('WhoWeAre', {
                  label: "who We Are",
    multiline: true
                }),
                PropertyPaneTextField('OurValue', {
                  label: "Our value"
                }), PropertyPaneTextField('description', {
                  label: "Description",
    multiline: true
                }),
              ]
            }
          ]
        }
      ]
    };
  }
}

inside the MyModalPopup.tsx:-在 MyModalPopup.tsx 中:-

import * as React from 'react';
import { IMyModalPopupProps } from './IMyModalPopupProps';
import { DefaultButton } from '@fluentui/react/lib/Button';
import { MYModal } from './MYModal';
import { MYModal2 } from './MYModal2';

interface IPopupState {
  showModal: string;
}

export default class MyModalPopup extends React.Component<IMyModalPopupProps, IPopupState> {
  constructor(props: IMyModalPopupProps, state: IPopupState) {
    super(props);
    this.state = {
      showModal: ''
    };
    this.handler = this.handler.bind(this);
    this.Buttonclick = this.Buttonclick.bind(this);
  }
  handler() {
    this.setState({
      showModal: ''
    })
  }
  private Buttonclick(e, whichModal) {
    e.preventDefault();

    this.setState({ showModal: whichModal });
  }
  public render(): React.ReactElement<IMyModalPopupProps> {

    const { showModal } = this.state;

    return (
      <div>

        <DefaultButton onClick={(e) => this.Buttonclick(e, 'our-value')} text="Our Value" />
        { showModal === 'our-value' && <MYModal2 OurValue={this.props.OurValue} myprops={this.state} handler={this.handler} />}

        <DefaultButton onClick={(e) => this.Buttonclick(e, 'who-we-are')} text="Who We Are" />
        { showModal === 'who-we-are' && <MYModal WhoWeAre={this.props.WhoWeAre} myprops={this.state} handler={this.handler} />}
      </div>
    );
  }
}

Actually, html-react-parser returns ReactJs object, and its return type is like React.createElement or like type of called JSX.实际上, html-react-parser返回的是 ReactJs 对象,它的返回类型类似于React.createElement或称为 JSX 的类型。

Using DOMPurify.sanitize will return safe pure HTML elements which those are different to the object that html-react-parser returns.使用DOMPurify.sanitize将返回安全的纯 HTML 元素,这些元素与html-react-parser返回的对象不同。 the risxss ESLint plugin will force you to use sanitizing with any kind of sanitize function or library, that I left an answer to your other question to how to Sanitize your string HTML . risxss ESLint 插件将强制您使用任何类型的 sanitize 函数或库进行 sanitizing,我在您的另一个问题中留下了一个关于如何清理字符串 HTML的答案。

Eventually , using sanitizing is better because is the html-react-parser will convert your string HTML to ReactJs object with some tiny changes that would be dangerous because it is possible to have some script of string HTML in the project and it maybe will be harmful it just remove the onclick or onload , etc, from HTML tags but sanitizing will remove all possible harmful tags.最终,使用清理会更好,因为html-react-parser会将您的字符串 HTML转换为 ReactJs 对象,并进行一些微小的更改,这将是危险的,因为项目中可能有一些字符串 HTML 的脚本,这可能是有害的它只是从 HTML 标签中删除onclickonload等,但清理将删除所有可能的有害标签。 also sanitizing will receive configuration, which means you can have your own options for sanitizing.消毒也会收到配置,这意味着您可以拥有自己的消毒选项

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM