FlawOpen

flawopen.com/XSS в JavaScript/Vue v-html

Риск XSS при использовании Vue v-html

Справочная страница
Простыми словами

Интерполяция Vue {{ comment }} похожа на записку за стеклом: угловые скобки остаются текстом. v-html просит браузер интерпретировать записку как HTML. Если разметкой управляет пользователь, браузер может принять её за структуру страницы или активное содержимое, создав риск XSS.

УЯЗВИМО — сырой HTML пользователя
<p v-html="comment"></p>
// comment интерпретируется как настоящая разметка
ИСПРАВЛЕНО — очищенный rich HTML
<script setup>
import { computed } from 'vue'
import DOMPurify from 'dompurify'

const props = defineProps({ comment: String })
const safeComment = computed(() =>
  DOMPurify.sanitize(props.comment ?? '', {
    ALLOWED_TAGS: ['p', 'strong', 'em'],
    ALLOWED_ATTR: []
  })
)
</script>

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

Очищайте rich HTML перед v-html

Используйте интерполяцию Vue {{ }}, если содержимое должно быть текстом. Если функция действительно требует пользовательский rich HTML, очищайте его поддерживаемой библиотекой, например DOMPurify, с узким списком разрешённого; привязывайте к v-html только очищенный результат. Обновляйте санитайзер и тестируйте разрешённую разметку. Очистка снижает риск, но не делает любой HTML безопасным во всех контекстах; используйте изолированный iframe, если активное содержимое должно оставаться недоверенным. Vue не компилирует содержимое v-html как Vue-шаблон.

Проверьте v-html и проследите поток данных

Найдите все привязки v-html. Для каждой установите источник, санитайзер и его конфигурацию, а также круг пользователей, которые увидят вывод. Отметьте прямой пользовательский ввод, сохранённые комментарии, поля CMS и ответы API; убедитесь, что обычный текст выводится через интерполяцию.

grep -rn "v-html" --include="*.vue" .

Частые вопросы

Это тот же риск, что и dangerouslySetInnerHTML в React?

Оба способа обходят обычное экранирование текста фреймворком и вставляют HTML в DOM. Для необходимого rich HTML используйте поддерживаемый санитайзер и не считайте очищенный результат универсально безопасным.

Источники

См. также XSS (межсайтовый скриптинг, CWE-79): как он работает и как его предотвратить в любом языке — flawopen.com WKWebView: безопасен ли HTML? Отражённый, хранимый и DOM-based XSS: в чём разница? Риски безопасности addJavascriptInterface в Android Защита Angular от XSS: безопасные значения и обходные API XSS из-за MIME sniffing: Content-Type и nosniff CSP и экранирование вывода: нужны ли оба?