FlawOpen

flawopen.com/XSS в JavaScript/dangerouslySetInnerHTML

Безопасен ли dangerouslySetInnerHTML в React?

Справочная страница
Краткий ответ

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

Почему обычному JSX это не нужно

РИСК — необработанный HTML
function Comment({ html }) {
  return <p dangerouslySetInnerHTML=
    {{ __html: html }} />;
}
БЕЗОПАСНО — обычная интерполяция JSX
function Comment({ text }) {
  return <p>{text}</p>;
}

Когда уместен dangerouslySetInnerHTML?

Используйте его только тогда, когда продукту необходимо сохранить ограниченный формат rich text, который нельзя представить обычными дочерними узлами React. CMS, редактор или Markdown-рендерер не становятся доверенными автоматически: сохранённый контент и результат рендерера могут содержать недоверенную разметку. Определите разрешённые элементы и атрибуты, очистите содержимое поддерживаемой библиотекой, например DOMPurify, и передайте результат в эту точку без дальнейших изменений.

Правильное применение

Очищайте на границе рендеринга

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

Ограничьте разрешённую разметку

Список запретов для известных тегов неполон: риск может исходить от атрибутов, URL-полей, пространств имён и поведения парсера. Составьте небольшой список необходимых элементов и атрибутов и настройте очиститель согласно ему. Отдельно проверьте ссылки и другие URL-атрибуты с учётом разрешённых продуктом адресов.

Как проверить код

grep -rn "dangerouslySetInnerHTML" --include="*.jsx" --include="*.tsx" .
Для каждого совпадения проследите путь значения от источника через все преобразования. Считайте пользовательский ввод, импортированный контент и сохранённый rich text недоверенными; убедитесь, что политика очистки подходит контексту вывода и результат не изменяется позднее.

Частые вопросы

Безопасен ли Markdown-рендеринг автоматически?

Это зависит от рендерера и его настроек. Проверьте, разрешён ли необработанный HTML и очищается ли результат; одно преобразование Markdown не делает HTML безопасным.

Это относится и к v-html во Vue?

Да. v-html также передаёт HTML браузеру без обычной текстовой интерполяции фреймворка. Считайте его HTML-точкой вывода и очищайте недоверенное содержимое по подходящей политике.

Источники

См. также XSS (межсайтовый скриптинг, CWE-79): как он работает и как его предотвратить в любом языке — flawopen.com Достаточно ли DOMPurify для безопасного innerHTML? Защищает ли Markdown от XSS? Защищает ли Svelte от XSS по умолчанию? Опасна ли загрузка SVG из-за XSS? Риск XSS при использовании Vue v-html WKWebView: безопасен ли HTML?