Политики безопасности контента

Библиотека Marked — это мощный парсер Markdown для JavaScript, который позволяет преобразовывать текст в формате Markdown в HTML. Одной из ключевых задач при использовании Marked является обеспечение безопасности, особенно когда исходный Markdown поступает от ненадёжных источников. Важно предотвратить внедрение вредоносного кода и XSS-атак, сохранив при этом возможность корректного отображения контента.

Настройка политик безопасности

Использование опции sanitize

Опция sanitize позволяет автоматически удалять потенциально опасные HTML-теги из Markdown-контента. Пример использования:

const marked = require('marked');

const markdownString = '<script>alert("XSS")</script> **Hello World**';
const html = marked(markdownString, { sanitize: true });

console.log(html); // <p>**Hello World**</p>

Особенности:

  • Полностью удаляет <script> и другие опасные элементы.
  • Не фильтрует Markdown-теги, которые не содержат HTML.
  • Устаревшая в последних версиях: рекомендуется использовать отдельные библиотеки для санитизации HTML, например DOMPurify.

Использование опции mangle и headerIds

Marked поддерживает опции, влияющие на генерацию HTML:

  • mangle — предотвращает автоматическую генерацию ссылок с электронной почтой, чтобы скрыть адреса от ботов.
  • headerIds — включает или отключает автоматическое добавление id к заголовкам, что важно для ссылок внутри страницы и безопасности.
marked.use({
  mangle: false,
  headerIds: false
});

Обработка пользовательского HTML

По умолчанию Marked позволяет включать HTML внутри Markdown. Для безопасного использования следует контролировать, какие теги разрешены. Пример интеграции с DOMPurify:

const DOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const purify = DOMPurify(window);

const unsafeMarkdown = '<img src=x oner ror=alert(1)> **Text**';
const rawHtml = marked.parse(unsafeMarkdown);
const safeHtml = purify.sanitize(rawHtml);

console.log(safeHtml); // <p><strong>Text</strong></p>

Преимущества такого подхода:

  • Полная фильтрация опасных атрибутов (onerror, onclick и других).
  • Сохраняется корректная разметка Markdown.
  • Совместимость с любыми кастомными расширениями Marked.

Настройка кастомных рендереров

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

const renderer = {
  link(href, title, text) {
    // Добавление атрибутов rel и target для безопасности
    return `<a href="${href}" title="${title || ''}" target="_blank" rel="noopener noreferrer">${text}</a>`;
  },
  image(href, title, text) {
    return `<img src="${href}" alt="${text}" title="${title || ''}" loading="lazy"/>`;
  }
};

marked.use({ renderer });

Особенности:

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

Политики Content Security Policy (CSP)

Для безопасного рендеринга Markdown в веб-приложении рекомендуется интегрировать CSP:

  • default-src ‘self’; script-src ‘none’; — запрещает выполнение любых скриптов.
  • img-src https: dat a:; — разрешает изображения только с HTTPS или встроенные data URI.
  • style-src ‘self’; — ограничивает подключение стилей.

Такой подход гарантирует, что даже при ошибках в фильтрации HTML не будет выполнен вредоносный код.

Выводы по безопасности

  • Не доверять встроенной опции sanitize для современных проектов.
  • Использовать сторонние библиотеки для полноценной фильтрации HTML, совместно с кастомными рендерерами Marked.
  • Контролировать все внешние ссылки и изображения, добавляя безопасные атрибуты.
  • Внедрять CSP на уровне фронтенда для дополнительной защиты.

Рекомендованная архитектура безопасного рендеринга Markdown

  1. Получение Markdown от пользователя или внешнего источника.
  2. Преобразование Markdown в HTML через Marked с кастомным рендерером.
  3. Санитизация полученного HTML через DOMPurify или аналог.
  4. Рендеринг в DOM с включенной политикой CSP.

Такой процесс обеспечивает баланс между функциональностью и безопасностью, предотвращает XSS и сохраняет корректное отображение Markdown-контента.