Как безопасно использовать 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
.