DevGang
Авторизоваться

Как безопасно использовать dangerouslySetInnerHTML в React

Dead Simple Chat позволяет добавлять чат в ваше приложение, используя мощный API-интерфейс JavaScript Chat и SDK. Вы можете добавить чат в любое React или веб-приложение за считанные минуты с помощью Dead Simple Chat.

Как следует из названия, dangerouslySetInnerHTML следует использовать с осторожностью. Это похоже на свойство InnerHTML, предоставляемое узлом DOM.

С помощью dangerouslySetInnerHTML вы можете установить HTML-код элемента. React не выполняет никакой очистки набора HTML, используя dangerouslySetInnerHTML.

Он называется dangerouslySetInnerHTML, потому что он опасен, если установленный HTML не фильтруется или не подвергается санации, поскольку он подвергает риску внедрения вредоносного кода, XSS-атаки и других угроз безопасности, которые могут поставить под угрозу приложение.

Следовательно, следует избегать использования dangerouslySetInnerHTML, если только это не является абсолютно необходимым, и перед dangerouslySetInnerHTML необходимо очистить входные данные HTML.

В этом сообщении блога мы рассмотрим несколько примеров того, как использовать dangerouslySetInnerHTML и как безопасно очистить HTML перед настройкой с помощью dangerouslySetInnerHTML.

Базовый пример использования

Вот базовый пример использования dangerouslySetInnerHTML.

import React from "react";

export default function App() {
  const htmlContent = "<p>This is raw <strong>HTML</strong> content.<p>";

  return (
    <div className="App">
      <h1>Raw HTML</h1>
      <div dangerouslySetInnerHTML={{ __html: htmlContent }}></div>
    </div>
  );
}

В приведенном выше примере мы устанавливаем необработанную строку HTML, хранящуюся в переменной htmlContent.

htmlContent будет установлен как внутренний HTML тега <div></div>. Мы передаем dangerouslySetInnerHTML prop объект с ключом __html, и значение должно содержать строку HTML, которую мы хотим установить.

HTML следует очистить перед использованием с dangerouslySetInnerHTML, поскольку он представляет угрозу безопасности. В приведенном выше примере HTML не является очисткой, и делать это не рекомендуется, поскольку это плохая практика и может привести к серьезной угрозе безопасности.

В следующем разделе мы увидим, как очистить HTML-строку перед установкой ее в качестве значения с помощью dangerouslySetInnerHTML.

Дезинфекция с помощью DOMPurify

В предыдущем разделе мы указали строку HTML и напрямую установили для нее значение dangerouslySetInnerHTML, что не является хорошей практикой.

В этом разделе мы будем использовать пакет DOMPurify для очистки нашей HTML-строки перед ее использованием в dangerouslySetInnerHTML.

Давайте сначала установим пакет DOMPurify с помощью npm install.

npm install dompurify

Затем мы обновим наш компонент для использования DOMPurify:

import React from "react";
import DOMPurify from "dompurify";

export default function App() {
  const htmlContent = "<p>This is raw <strong>HTML</strong> content.<p>";
  const sanitizedHtmlContent = DOMPurify.sanitize(htmlContent);
  return (
    <div className="App">
      <h1>Raw HTML</h1>
      <div dangerouslySetInnerHTML={{ __html: sanitizedHtmlContent }}></div>
    </div>
  );
}

Использовать библиотеку DOMPurify очень просто, нам просто нужно вызвать метод santize в библиотеке DOMPurify, и он вернет очищенную версию HTML.

Затем мы можем передать очищенную версию в опору dangerouslySetInnerHTML.

Проверка очистки HTML

Чтобы проверить, работает ли наш DOMPurify, мы добавим полезную нагрузку XSS в нашу HTML-строку и посмотрим, правильно ли наш DOMPurify экранирует HTML-скрипт.

import React from "react";
import DOMPurify from "dompurify";

export default function App() {
  const htmlContent = "<script>alert(1);</script>";
  const sanitizedHtmlContent = DOMPurify.sanitize(htmlContent);
  return (
    <div className="App">
      <h1>Raw HTML</h1>
      <div dangerouslySetInnerHTML={{ __html: sanitizedHtmlContent }}></div>
    </div>
  );
}

Мы обновили наш htmlContent до <script>alert(1);</script>, и если наш HTML не будет правильно очищен, на странице отобразится предупреждение со значением 1.

Помимо DOMPurify существуют и другие библиотеки очистки, которые вы можете использовать, например sanitize-HTML. Но при выборе библиотеки убедитесь, что вы используете библиотеку, которая активно развивается, имеет большую базу пользователей и широко используется.

Альтернативы, которые следует учитывать перед использованием dangerouslySetInnerHTML

dangerouslySetInnerHTML следует использовать только тогда, когда это абсолютно необходимо, и его следует избегать, когда это возможно, из-за рисков безопасности.

Прежде чем использовать dangerouslySetInnerHTML, всегда следует учитывать другие параметры, и вот некоторые из них, которые вам следует рассмотреть, но обязательно сначала санируйте свой HTML с помощью такой библиотеки, как DOMPurify:

  • Сначала попробуйте использовать JSX: Сначала вам следует попробовать использовать JSX. Если у вас есть устаревший код, который вы хотите интегрировать, или вы интегрируете какую-либо стороннюю библиотеку, попробуйте использовать ее JSX и со ссылками и используйте dangerouslySetInnerHTML только в крайнем случае.
  • Используйте библиотеку, которая преобразует HTML в JSX: доступно несколько библиотек, которые анализируют HTML в JSX. Вы также можете попробовать использовать эти библиотеки, некоторые из популярных вариантов включают в себя:
  • html-react-parser: позволяет анализировать необработанный HTML и конвертировать его в элементы React. Это более безопасная альтернатива dangerouslySetInnerHTML. Однако вам все равно необходимо очистить HTML. На момент написания эта библиотека имела 1,6 тыс. звезд на Github и 990 820 загрузок в неделю на npm.
  • response-html-parser: это также позволяет конвертировать необработанный HTML в реагирующие компоненты и похоже на html-react-parser. На момент написания у него 742 запуска на github и 277 тысяч загрузок в неделю на NPM. Также следует отметить, что последний раз оно обновлялось в 2020 году.

Перед использованием этих библиотек обязательно очистите HTML с помощью библиотек очистки HTML, таких как DOMPurify.

Сценарии, в которых можно использовать dangerouslySetInnerHTML

Иногда использование dangerouslSetInnerHTML неизбежно, и бывают случаи, когда без использования dangerouslSetInnerHTML не обойтись. обсудить некоторые из этих сценариев:

  • Данные HTML, поступающие из надежного источника: когда ваш HTML-контент поступает из надежного источника, такого как ваша система управления контентом, или из контента, сгенерированного сервером. В этих случаях вы можете использовать dangerouslSetInnerHTML. Но убедитесь, что вы доверяете источнику данных.
  • Правильно очищенный контент. Вы можете безопасно использовать контент dangerouslSetInnerHTML, который надлежащим образом очищен. Убедитесь, что вы используете надежную и хорошо протестированную библиотеку очистки, чтобы избежать любых небезопасных тегов и кода XSS.
  • При интеграции сторонних библиотек: некоторые сторонние библиотеки плохо интегрируются в React. В таких случаях вам придется использовать dangerouslSetInnerHTML для интеграции библиотеки с вашим кодом. Но прежде чем делать это, убедитесь, что вы доверяете библиотеке, хорошо проверены и не подвергаете свое приложение никакому риску безопасности, а генерируемый контент хорошо очищен.

Создание редактора Markdown в React с использованием ShowDown, DOMPurify и dangerouslSetInnerHTML

Давайте создадим редактор Markdown, который отображает выходные данные Markdown в HTML в режиме реального времени.

Чтобы создать это приложение, мы создадим компонент, который будет принимать уценку и конвертировать ее в HTML.

Мы также будем использовать библиотеку, которая будет работать следующим образом:

  • Создайте компонент React. Примите текст Markdown в качестве реквизита.
  • Используйте ShowDown для преобразования Markdown в HTML
  • Используйте DOMPurify для очистки визуализированного HTML.

Создание MarkDownViewer

Мы создадим компонент MarkdownViewer.js, который будет принимать уценку в качестве реквизита, конвертировать ее в HTML и отображать на экране.

Создайте файл с именем src/MarkdownViewer.js и добавьте следующий код:

import showdown from "showdown";
import DOMPurify from "dompurify";
import React from "react";

function MarkdownViewer({ md, styles, className }) {
  const converter = new showdown.Converter();
  const html = converter.makeHtml(md);
  const sanitizedHTML = DOMPurify.sanitize(html);

  return (
    <div
      styles={styles}
      className={className}
      dangerouslySetInnerHTML={{ __html: sanitizedHTML }}
    ></div>
  );
}

export default MarkdownViewer;

В приведенном выше коде мы создали компонент MarkdownViewer, сначала импортировали зависимости showdown и dompurify.

Вы можете установить их с помощью npm

npm install showdown
npm install dompurify

Затем мы создаем объект-конвертер и конвертируем уценку в html.

const html = converter.makeHtml(md);

Затем мы очищаем сгенерированный HTML с помощью библиотеки DOMPurify:

const sanitizedHTML = DOMPurify.sanitize(html);

Наконец, мы устанавливаем сгенерированный HTML как dangerouslySetInnerHTML в тег div.

 return (
    <div
      styles={styles}
      className={className}
      dangerouslySetInnerHTML={{ __html: sanitizedHTML }}
    ></div>
  );

Создание редактора

Компонент Editor очень прост, он будет содержать текстовую область и принимать метод onChange в качестве свойства.

Создайте файл с именем src/Editor.js для хранения нашего компонента редактора.

Мы будем вызывать метод onChange из свойства, когда значение текстовой области изменится.

export default function Editor({ onChange, styles, className }) {
  return (
    <textarea
      styles={styles}
      className={className}
      onChange={onChange}
    ></textarea>
  );
}

Собираем все это вместе

Теперь давайте откроем наш файл src/App.js и импортируем компоненты MarkdownViewer и Editor.

Мы подключим прослушиватель onChange к компоненту Editor, получим значение из редактора и установим его в качестве свойства для компонента MarkdownViewer для отображения Markdown, введенного пользователем.

import React, { useState } from "react";
import Editor from "./Editor";
import MarkDownViewer from "./MarkdownViewer";
import "./styles.css";

export default function App() {
  const [editorValue, setEditorValue] = useState("");
  function handleOnChange(event) {
    setEditorValue(event.target.value);
  }

  return (
    <div className={"container"}>
      <Editor className={"half"} onChange={handleOnChange} />
      <MarkDownViewer className={"half"} md={editorValue} />
    </div>
  );
}

В приведенной выше обложке мы создали переменную состояния, называемую editorValue, и метод, называемый handleOnChange.

Мы передаем метод handleOnChange в качестве реквизита компоненту Editor. Когда значение изменяется в компоненте Editor, мы обновляем editorValue при изменении текстовой области.

Затем мы передаем editorValue компоненту просмотра Markdown.

Серверы TURN с лимитной оплатой

  • Глобальный таргетинг по географическому местоположению: автоматически направляет трафик на ближайшие серверы для минимально возможной задержки и высочайшего качества работы. задержка менее 50 мс в любой точке мира
  • Серверы в 12 регионах мира: Торонто, Майами, Сан-Франциско, Амстердам, Лондон, Франкфурт, Бангалор, Сингапур, Сидней (скоро: Южная Корея, Япония и Оман)
  • Низкая задержка: задержка менее 50 мс в любой точке мира.
  • Экономичность: оплата по факту использования, а также скидки на пропускную способность и объем.
  • Простое администрирование: получайте журналы использования, электронные письма, когда учетные записи достигают пороговых ограничений, записи о выставлении счетов, а также поддержку по электронной почте и телефону.
  • Соответствие стандартам: соответствует RFC 5389, 5769, 5780, 5766, 6062, 6156, 5245, 5768, 6336, 6544, 5928 по UDP, TCP, TLS и DTLS.
  • Мультитенантность: создайте несколько учетных данных и разделите их использование по клиентам или различным приложениям. Получайте журналы использования, записи о выставлении счетов и оповещения о пороговых значениях.
  • Корпоративная надежность: время безотказной работы 99,999 % по соглашению об уровне обслуживания.
  • Масштаб предприятия: без ограничений на одновременный или общий трафик. Лимитные серверы TURN обеспечивают масштабируемость предприятия
  • 50 ГБ/мес бесплатно: получайте 50 ГБ каждый месяц бесплатного использования сервера TURN с бесплатным планом.
  • Работает на портах 80 и 443.
  • Поддержка TURNS + SSL для обеспечения соединений через брандмауэры с глубокой проверкой пакетов.
  • Поддержка STUN
  • Поддерживает TCP и UDP.

Возможно, вас заинтересуют другие наши статьи.

Заключение

В этом сообщении блога мы узнали, что такое dangerouslySetInnerHTML и как безопасно использовать его в нашем приложении.

Мы также рассмотрели способы избежать использования dangerouslySetInnerHTML и его альтернатив, а также рассмотрели способы безопасного экранирования HTML-кода перед его рендерингом с использованием dangerouslySetInnerHTML.

Источник:

#JavaScript #React #HTML
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться