MDX сочетает возможности Markdown и JSX, что позволяет встраивать компоненты React прямо в текст. Это даёт мощные возможности для динамических страниц, документации и блогов, однако открывает риски, связанные с безопасностью пользовательского контента. Основная угроза заключается в возможности внедрения вредоносного кода через JSX или HTML, встроенный в MDX.
Любой пользовательский MDX должен проходить этап валидации до рендеринга. Основные стратегии:
Ограничение допустимых элементов Использовать
специализированные парсеры, например remark с плагином
remark-allowed-elements, чтобы разрешать только безопасный
набор тегов. Например, можно разрешить p,
h1-h6, ul, ol, li,
strong, em, a, исключив любые
<script>, <iframe> или
произвольные компоненты JSX.
Санитизация HTML Любой HTML, встроенный в MDX,
должен проходить через санитайзер, такой как DOMPurify. Он
удаляет опасные атрибуты (onload, onclick и
подобные) и запрещённые теги.
Ограничение JSX-компонентов Для MDX-файлов с поддержкой компонентов необходимо явно перечислять, какие компоненты допустимы. Пример:
import { MDXProvider } from '@mdx-js/react';
import SafeButton from './SafeButton';
import SafeImage from './SafeImage';
const components = {
Button: SafeButton,
Image: SafeImage
};
<MDXProvider components={components}>
<MDXContent />
</MDXProvider>
Любой пользовательский JSX вне списка components должен
быть запрещён.
MDX позволяет вставлять произвольный JavaScript через JSX, что создаёт риск выполнения вредоносного кода. Стратегии минимизации:
Серверная компиляция MDX-файлы обрабатываются на сервере, и конечный результат рендерится как статический HTML. Это исключает выполнение произвольного JS на клиенте.
Песочница для компонентов Использовать
библиотеку вроде vm2 для безопасного выполнения кода, если
динамические выражения неизбежны.
Ограничение импорта Не разрешать импорт внешних
библиотек из пользовательского контента. Любые необходимые компоненты
должны быть предоставлены через заранее подготовленный
MDXProvider.
MDX часто используется для публикации статей с ссылками и медиа-контентом. Для безопасности:
rel="noopener noreferrer" ко всем
внешним ссылкам.Пример безопасного рендеринга ссылок с использованием
remark и rehype:
import rehypeExternalLinks from 'rehype-external-links';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeExternalLinks, { target: '_blank', rel: ['noopener', 'noreferrer'] })
.use(rehypeStringify);
const safeHtml = processor.processSync(mdxContent).toString();
Для защиты от атак через перегрузку:
Даже при строгой фильтрации важно отслеживать попытки внедрения опасного контента. Следует вести:
Эти меры обеспечивают безопасную работу с пользовательским MDX-контентом и предотвращают большинство уязвимостей, связанных с внедрением вредоносного кода.