XSS (Cross-Site Scripting) — это класс уязвимостей веб-приложений, при котором злоумышленник внедряет вредоносный скрипт в контент, который потом выполняется в браузере пользователей. Основная опасность заключается в возможности украсть данные сессии, изменить отображение страницы или выполнить действия от имени пользователя без его ведома.
Существует несколько типов XSS:
В веб-приложениях, где используется Markdown для ввода контента
пользователями, XSS-риски увеличиваются. Markdown часто рендерится в
HTML, и любой небезопасный HTML или атрибуты могут стать каналом для
выполнения скриптов. Например, вставка
<img src=x oner ror=alert(1)> в Markdown приведёт к
выполнению JavaScript при рендере, если преобразование в HTML не
фильтрует опасные теги.
Remark — это библиотека для разбора Markdown в AST (Abstract Syntax Tree) и обратного преобразования. Она предоставляет мощный механизм для обработки, трансформации и валидации Markdown-контента. Rehype выполняет аналогичную роль для HTML: преобразует HTML в AST и позволяет безопасно манипулировать узлами, включая фильтрацию потенциально опасных элементов.
Remark и Rehype используются совместно через плагины, создавая цепочку преобразования:
Rehype предоставляет плагины, которые фильтруют небезопасные теги и
атрибуты. Наиболее распространённый подход — использовать
rehype-sanitize. Он позволяет определить белый список тегов
и атрибутов, исключая любые скриптовые конструкции:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeSanitize from 'rehype-sanitize';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeSanitize) // базовая безопасная фильтрация
.use(rehypeStringify);
const html = await processor.process(someMarkdown);
rehype-sanitize может быть настроен с собственным белым
списком тегов и атрибутов, что обеспечивает строгий контроль над
безопасным HTML.
Внешние ссылки могут быть использованы для XSS через
jav * ascript: URI или фишинговые перенаправления.
rehype-sanitize поддерживает настройку
protocols для разрешённых схем, например только
http, https, mailto.
import { defaultSchema } from 'hast-util-sanitize';
const schema = {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
a: {
...defaultSchema.attributes.a,
href: ['http', 'https', 'mailto'], // разрешённые протоколы
},
},
};
Remark позволяет отключить или ограничить встроенный HTML с помощью
плагинов вроде remark-gfm или remark-html.
Если HTML нужен, его следует обрабатывать через Rehype с последующей
санитацией, иначе лучше полностью запретить его:
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeSanitize from 'rehype-sanitize';
// Не используем встроенный HTML в Markdown
Для проектов с расширенными требованиями безопасности рекомендуется создавать кастомные схемы для Rehype:
p, strong,
em, ul, li, a,
code, pre, blockquotehref для ссылок,
className для стилизацииon*) и style
с JavaScriptimport rehypeSanitize from 'rehype-sanitize';
const customSchema = {
tagNames: ['p', 'strong', 'em', 'ul', 'li', 'a', 'code', 'pre', 'blockquote'],
attributes: {
a: ['href'],
code: ['className'],
},
protocols: {
href: ['http', 'https', 'mailto'],
},
};
Эффективная защита XSS строится на комбинации плагинов Remark и Rehype:
Такая цепочка обеспечивает чистый и безопасный HTML-код, минимизируя риск XSS.
jav * ascript:, data:,
vb * script:.Remark и Rehype вместе создают мощный инструмент для безопасной работы с пользовательским Markdown и HTML, предоставляя гибкие механизмы фильтрации и контроля за структурой документа, что критически важно для предотвращения XSS-атак.