Безопасность
Сообщение об уязвимостях
Когда поступает сообщение об уязвимости, оно сразу становится нашей главной задачей, и штатный сотрудник бросает все дела, чтобы заняться ее устранением. Чтобы сообщить об уязвимости, напишите, пожалуйста, по адресу security@vuejs.org.
Хотя новые уязвимости обнаруживаются редко, мы также рекомендуем всегда использовать последние версии Vue и его официальных библиотек-компаньонов, чтобы обеспечить максимальную безопасность вашего приложения.
Правило № 1: Никогда не используйте ненадежные шаблоны
Самое главное правило безопасности при использовании Vue - никогда не использовать в качестве шаблона компонента ненадежное содержимое. Это равносильно разрешению произвольного выполнения JavaScript в вашем приложении, и, что еще хуже, может привести к нарушениям в работе сервера, если код будет выполняться во время рендеринга на стороне сервера. Пример такого использования:
js
Vue.createApp({
template: `<div>` + userProvidedString + `</div>` // НИКОГДА ТАК НЕ ДЕЛАЙТЕ
}).mount('#app')
Шаблоны Vue компилируются в JavaScript, и выражения, содержащиеся в шаблонах, будут выполняться в процессе рендеринга. Хотя выражения оцениваются в конкретном контексте рендеринга, из-за сложности потенциальных глобальных сред выполнения фреймворк, подобный Vue, не в состоянии полностью защитить вас от возможного выполнения вредоносного кода без нереальных затрат на производительность. Наиболее простой способ избежать этой категории проблем - убедиться в том, что содержимое шаблонов Vue всегда доверено и полностью контролируется вами.
Что делает Vue для вашей защиты
HTML-содержимое
При использовании шаблонов или функций рендеринга содержимое автоматически экранируется. Это означает, что в данном шаблоне:
template
<h1>{{ userProvidedString }}</h1>
если userProvidedString
содержит:
js
'<script>alert("привет")</script>'
то он будет приведен к следующему виду HTML:
template
<script>alert("hi")</script>
тем самым предотвращая инъекцию скрипта. Для экранирования используются собственные API браузера, например textContent
, поэтому уязвимость может существовать только в том случае, если уязвим сам браузер.
Связывание атрибутов
Аналогичным образом автоматически экранируются и динамическая привязка атрибутов. Это означает, что в данном шаблоне:
template
<h1 :title="userProvidedString">
привет
</h1>
если userProvidedString
содержит:
js
'" onclick="alert(\'привет\')'
то он будет приведен к следующему виду HTML:
template
" onclick="alert('привет')
Таким образом, предотвращается закрытие атрибута title
для внедрения нового произвольного HTML. Это экранирование выполняется с помощью собственных API браузера, например setAttribute
, поэтому уязвимость может существовать только в том случае, если уязвим сам браузер.
Потенциальные угрозы
В любом веб-приложении допускать выполнение непроверенного, предоставленного пользователем содержимого в виде HTML, CSS или JavaScript потенциально опасно, поэтому по возможности следует избегать этого. Однако бывают случаи, когда некоторый риск может быть допустимым.
Например, такие сервисы, как CodePen и JSFiddle, позволяют выполнять предоставленное пользователем содержимое, но в контексте, где это ожидается, и в некоторой степени "песочницы" внутри iframe. В тех случаях, когда важная функция по своей сути требует определенного уровня уязвимости, ваша команда должна взвесить важность этой функции и худшие сценарии, к которым может привести уязвимость.
HTML-инъекция
Как вы узнали ранее, Vue автоматически экранирует HTML-содержимое, предотвращая случайное внедрение исполняемого HTML в ваше приложение. Однако в случаях, когда вы знаете, что HTML безопасен, вы можете явно экранировать HTML-содержимое:
Использование шаблона:
template<div v-html="userProvidedHtml"></div>
Использование render-функции:
jsh('div', { innerHTML: this.userProvidedHtml })
Использование функции рендеринга в JSX:
jsx<div innerHTML={this.userProvidedHtml}></div>
Предупреждение
Пользовательский HTML никогда не может считаться на 100% безопасным, если он не находится в "песочнице" iframe или в той части приложения, где он может быть доступен только пользователю, написавшему этот HTML. Кроме того, разрешение пользователям писать собственные шаблоны Vue таит в себе аналогичные опасности.
URL-инъекция
В таком URL:
template
<a :href="userProvidedUrl">
нажми на меня
</a>
Существует потенциальная проблема безопасности, если URL не был "продезинфицирован" для предотвращения выполнения JavaScript с помощью javascript:
. Существуют такие библиотеки, как sanitize-url, чтобы помочь с этим, но обратите внимание: если вы когда-либо выполняли очистку URL-адресов на фронтенде, у вас уже есть проблема с безопасностью. URL-адреса, предоставляемые пользователями, всегда должны подвергаться санитарной обработке в бэкенде еще до сохранения в базе данных. В этом случае проблема не будет возникать у каждого клиента, подключающегося к вашему API, включая нативные мобильные приложения. Также следует отметить, что даже при использовании дезинфицированных URL-адресов Vue не может гарантировать, что они ведут к безопасным местам назначения.
Инъекция стиля
Рассмотрим такой пример:
template
<a
:href="sanitizedUrl"
:style="userProvidedStyles"
>
нажми на меня
</a>
Предположим, что sanitizedUrl
был подвергнут санитарной обработке, так что это точно настоящий URL, а не JavaScript. С учётом userProvidedStyles
, злоумышленники все еще могут предоставить CSS для "захвата клика", например, стилизовать ссылку в прозрачный бокс над кнопкой "Войти". Тогда если сайт https://user-controlled-website.com/
построен таким образом, чтобы напоминать страницу входа в систему вашего приложения, они могли просто перехватить настоящую регистрационную информацию пользователя.
Можно представить себе, что разрешение на использование пользовательского содержимого для элемента <style>
создаст еще большую уязвимость, предоставляя пользователю полный контроль над стилем всей страницы. Именно поэтому Vue предотвращает отрисовку тегов стиля внутри шаблонов, например:
template
<style>{{ userProvidedStyles }}</style>
Чтобы полностью обезопасить пользователей от перехвата кликов (Clickjacking), мы рекомендуем предоставлять полный контроль над CSS только внутри "песочницы" iframe. В качестве альтернативы, при предоставлении пользователю контроля через привязку стилей, мы рекомендуем использовать объектный синтаксис и разрешать пользователям предоставлять значения только для определенных свойств, которые они могут контролировать, например, так:
template
<a
:href="sanitizedUrl"
:style="{
color: userProvidedColor,
background: userProvidedBackground
}"
>
нажми на меня
</a>
JavaScript-инъекция
Мы настоятельно рекомендуем не выводить элемент <script>
во Vue, поскольку шаблоны и render-функции не должны иметь побочных эффектов. Однако это не единственный способ включения строк, которые во время выполнения будут оцениваться как JavaScript.
Каждый HTML-элемент имеет атрибуты со значениями, принимающими строки JavaScript, такие как: onclick
, onfocus
и onmouseenter
. Привязка пользовательского JavaScript к любому из этих атрибутов событий представляет собой потенциальный риск безопасности, поэтому ее следует избегать.
Предупреждение
Пользовательский JavaScript никогда не может считаться на 100% безопасным, если он не находится в "песочнице" iframe или в той части приложения, где он может быть доступен только пользователю, написавшему этот JavaScript.
Иногда мы получаем сообщения об уязвимостях, связанных с возможностью осуществления межсайтового скриптинга (XSS) в шаблонах Vue. В целом мы не считаем такие случаи реальными уязвимостями, поскольку не существует практического способа защитить разработчиков от двух сценариев, при которых возможен XSS:
Разработчик явно просит Vue отображать предоставленный пользователем непроверенный контент в виде шаблонов Vue. Это небезопасно по своей сути, и у Vue нет возможности узнать источник.
Разработчик устанавливает Vue на всю HTML-страницу, которая, как оказалось, содержит серверный рендеринг и пользовательский контент. По сути, это та же проблема, что и №1, но иногда разработчики могут делать это, не осознавая. Это может привести к возможным уязвимостям, когда злоумышленник предоставляет HTML, который безопасен как обычный HTML, но небезопасен как шаблон Vue. Лучшая практика - никогда не устанавливать Vue на узлы, которые могут содержать серверный и пользовательский контент.
Лучшие практики
Общее правило заключается в том, что если вы позволяете выполнять непроверенный, предоставленный пользователем контент (в виде HTML, JavaScript или даже CSS), то вы открываете себя для атак. Это правило справедливо как для Vue, так и для других фреймворков или вообще без них.
Помимо рекомендаций, приведенных выше в отношении потенциальных опасностей, мы также рекомендуем ознакомиться с этими ресурсами:
Затем используйте полученные знания для анализа исходного кода зависимостей на предмет потенциально опасных паттернов, если какие-либо из них включают компоненты сторонних разработчиков или иным образом влияют на то, что выводится в DOM.
Координация работы с бэкендом
Уязвимости безопасности HTTP, такие как подделка межсайтовых запросов (CSRF/XSRF) и межсайтовое включение сценариев (XSSI), в основном решаются на бэкенде, поэтому Vue их не касается. Тем не менее нелишним будет пообщаться с командой бэкенда, чтобы узнать, как лучше взаимодействовать с их API, например, передавать токены CSRF при отправке форм.
Рендеринг на стороне сервера (SSR)
При использовании SSR возникают некоторые дополнительные проблемы с безопасностью, поэтому во избежание уязвимостей обязательно следуйте лучшим практикам, описанным в нашей документации по SSR.