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

Для использования Marked вместе с DOMPurify необходимо установить обе библиотеки через npm или подключить через CDN. В среде Node.js это делается командой:

npm install marked dompurify jsdom

Для браузера можно подключить через CDN:

<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>

В Node.js потребуется использовать jsdom для создания виртуального DOM, необходимого DOMPurify:

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

Основная идея интеграции

Marked преобразует Markdown в HTML, но этот HTML может содержать потенциально опасный код, например <script> или атрибуты onload, onclick. DOMPurify выполняет санитизацию, удаляя все потенциально опасные элементы, оставляя безопасный HTML.

Простейший пример:

const markdown = "# Заголовок\n\n<script>alert('XSS');</script>";
const html = marked.parse(markdown);
const safeHtml = DOMPurify.sanitize(html);

console.log(safeHtml);
// <h1>Заголовок</h1>

В этом примере <script> полностью удаляется, а заголовок сохраняется.

Настройка DOMPurify

DOMPurify предоставляет гибкие возможности для контроля безопасного HTML. Основные опции:

  • ALLOWED_TAGS — список разрешённых тегов
  • ALLOWED_ATTR — список разрешённых атрибутов
  • FORBID_TAGS — список запрещённых тегов
  • FORBID_ATTR — список запрещённых атрибутов

Пример:

const clean = DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'li', 'h1', 'h2', 'h3'],
    ALLOWED_ATTR: ['href', 'title']
});

Это позволяет точно контролировать, какие элементы Markdown будут видны на странице после преобразования.

Использование с динамическим контентом

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

const container = document.getElementById('content');
const markdownText = "# Новый заголовок\n\n[Ссылка](https://example.com)";
container.innerHTML = DOMPurify.sanitize(marked.parse(markdownText));

Таким образом, любой пользовательский Markdown преобразуется в безопасный HTML, готовый для вставки в DOM.

Кастомизация рендерера Marked

Marked позволяет создавать собственные рендереры, например для обработки ссылок или картинок:

const renderer = new marked.Renderer();

renderer.link = function(href, title, text) {
    return `<a href="${href}" title="${title || ''}" target="_blank" rel="noopener noreferrer">${text}</a>`;
};

const html = marked.parse(markdownText, { renderer });
const safeHtml = DOMPurify.sanitize(html);

Использование кастомного рендерера позволяет:

  • Автоматически добавлять атрибуты безопасности (rel="noopener")
  • Контролировать внешний вид ссылок и изображений
  • Ограничивать HTML-теги при генерации

Защита от XSS и небезопасных ссылок

DOMPurify также поддерживает фильтрацию URL:

const cleanHtml = DOMPurify.sanitize(html, {
    ALLOWED_URI_REGEXP: /^https?:\/\//
});

Это исключает использование jav * ascript: и других небезопасных схем в ссылках.

Интеграция с фреймворками

React, Vue, Angular: Markdown часто используется для рендеринга контента. Важно применять DOMPurify перед вставкой HTML:

React:

import DOMPurify from 'dompurify';
import { marked } from 'marked';

function MarkdownRenderer({ content }) {
    const html = DOMPurify.sanitize(marked.parse(content));
    return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

Vue:

<template>
  <div v-html="safeHtml"></div>
</template>

<script>
import DOMPurify from 'dompurify';
import { marked } from 'marked';

export default {
  props: ['content'],
  computed: {
    safeHtml() {
      return DOMPurify.sanitize(marked.parse(this.content));
    }
  }
}
</script>

Прямое использование v-html или dangerouslySetInnerHTML безопасно только после санитизации через DOMPurify.

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

DOMPurify поддерживает хуки, позволяющие модифицировать HTML перед или после санитизации:

DOMPurify.addHook('afterSanitizeAttributes', function(node) {
    if (node.tagName === 'A') {
        node.setAttribute('rel', 'noopener noreferrer');
        node.setAttribute('target', '_blank');
    }
});

Совмещение с кастомным рендерером Marked позволяет полностью контролировать структуру и безопасность HTML.

Практические рекомендации

  • Всегда использовать DOMPurify при работе с пользовательским Markdown.
  • Настраивать ALLOWED_TAGS и ALLOWED_ATTR в зависимости от контекста.
  • Для ссылок добавлять rel="noopener noreferrer" и target="_blank" для безопасности.
  • Проверять URL через ALLOWED_URI_REGEXP, чтобы исключить потенциально опасные схемы.
  • Использовать хуки DOMPurify для дополнительной кастомизации и защиты.

Интеграция Marked с DOMPurify обеспечивает безопасное и гибкое отображение Markdown, предотвращая XSS и сохраняя удобство редактирования контента.