rehype-sanitize: санитизация HTML

rehype-sanitize — это плагин для экосистемы Rehype, предназначенный для безопасной обработки HTML-контента. Он используется для предотвращения внедрения вредоносного кода (XSS-атак) при работе с HTML, полученным из ненадёжных источников. На практике это особенно важно при обработке пользовательского ввода или контента, поступающего из внешних источников, таких как CMS или комментарии.

Плагин обеспечивает фильтрацию HTML-элементов и атрибутов на основе конфигурации, которая задаёт разрешённые теги, атрибуты и схемы URI.


Подключение и базовое использование

Установка производится через npm:

npm install rehype rehype-sanitize

Для базового применения достаточно импортировать плагин и передать его в цепочку обработки Rehype:

import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeStringify from 'rehype-stringify';
import rehypeSanitize from 'rehype-sanitize';

const html = '<div><script>alert("XSS")</script><p>Текст</p></div>';

const result = await unified()
  .use(rehypeParse, { fragment: true })
  .use(rehypeSanitize)
  .use(rehypeStringify)
  .process(html);

console.log(result.toString());
// Вывод: <div><p>Текст</p></div>

В этом примере script тег был удалён, так как по умолчанию rehype-sanitize блокирует потенциально опасные элементы.


Конфигурация правил

rehype-sanitize использует объект schema для определения допустимых тегов, атрибутов и протоколов. Встроенный default schema достаточно строгий, но часто требуется расширение под конкретные задачи.

Пример расширенной конфигурации:

import { defaultSchema } from 'hast-util-sanitize';

const mySchema = {
  ...defaultSchema,
  tagNames: [...defaultSchema.tagNames, 'span'],
  attributes: {
    ...defaultSchema.attributes,
    span: ['class'],
    a: [...(defaultSchema.attributes.a || []), 'target', 'rel']
  },
  protocols: {
    ...defaultSchema.protocols,
    a: { ...defaultSchema.protocols?.a, target: ['_blank'] }
  }
};

const safeHtml = await unified()
  .use(rehypeParse, { fragment: true })
  .use(rehypeSanitize, mySchema)
  .use(rehypeStringify)
  .process('<a href="http://example.com" target="_blank" rel="noopener">Ссылка</a><span class="highlight">Текст</span>');

console.log(safeHtml.toString());

Здесь разрешается использование тега span с атрибутом class, а ссылки получают дополнительные атрибуты безопасности.


Работа с атрибутами и протоколами

С помощью rehype-sanitize можно контролировать:

  • Разрешённые атрибуты для каждого тега;
  • Разрешённые схемы URI (например, http, https, mailto);
  • Специфические значения атрибутов, такие как target="_blank" для ссылок.

Пример строгой фильтрации URL:

const schema = {
  tagNames: ['a'],
  attributes: { a: ['href'] },
  protocols: { a: { href: ['http', 'https'] } }
};

const html = '<a href="jav * ascript:alert(1)">Click</a><a href="https://site.com">Valid</a>';

const safe = await unified()
  .use(rehypeParse, { fragment: true })
  .use(rehypeSanitize, schema)
  .use(rehypeStringify)
  .process(html);

console.log(safe.toString());
// Вывод: <a href="https://site.com">Valid</a>

Все ссылки с опасными протоколами автоматически удаляются.


Интеграция с Remark

Для проектов, где исходный контент находится в Markdown, часто используют связку Remark → Rehype → rehype-sanitize:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeSanitize from 'rehype-sanitize';

const markdown = 'Пример [ссылки](jav * ascript:alert(1)) и <b>HTML</b>';

const processed = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeSanitize)
  .use(rehypeStringify)
  .process(markdown);

console.log(processed.toString());
// Вывод: Пример <a>ссылки</a> и <b>HTML</b>

Плагин удаляет опасные URL и небезопасные теги, сохраняя при этом допустимый HTML, встроенный в Markdown.


Расширенные возможности

  1. Кастомные схемы Можно полностью определить набор разрешённых тегов и атрибутов, создавая белый список под конкретные требования приложения.

  2. Смешанные HTML/Markdown потоки Схема позволяет фильтровать HTML, который встроен в Markdown, при этом не ломая корректные элементы Markdown.

  3. Безопасность ссылок и атрибутов rehype-sanitize предотвращает использование атрибутов вроде onload, onclick, а также запрещает схемы jav * ascript: и data: для URL.


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

  • Использовать defaultSchema как отправную точку, а затем расширять его под нужды проекта.
  • Для пользовательского контента всегда фильтровать любые теги, способные выполнять скрипты.
  • Проверять все пользовательские URL через protocols для предотвращения XSS через jav * ascript:.
  • Объединять с remark-rehype, чтобы безопасно конвертировать Markdown в HTML с последующей санитизацией.

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