Skip to content

Безопасность

Сообщение об уязвимостях

Когда поступает сообщение об уязвимости, оно сразу становится нашей главной задачей, и штатный сотрудник бросает все дела, чтобы заняться ее устранением. Чтобы сообщить об уязвимости, напишите, пожалуйста, по адресу 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
&lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;

тем самым предотвращая инъекцию скрипта. Для экранирования используются собственные API браузера, например textContent, поэтому уязвимость может существовать только в том случае, если уязвим сам браузер.

Связывание атрибутов

Аналогичным образом автоматически экранируются и динамическая привязка атрибутов. Это означает, что в данном шаблоне:

template
<h1 :title="userProvidedString">
  привет
</h1>

если userProvidedString содержит:

js
'" onclick="alert(\'привет\')'

то он будет приведен к следующему виду HTML:

template
&quot; onclick=&quot;alert('привет')

Таким образом, предотвращается закрытие атрибута title для внедрения нового произвольного HTML. Это экранирование выполняется с помощью собственных API браузера, например setAttribute, поэтому уязвимость может существовать только в том случае, если уязвим сам браузер.

Потенциальные угрозы

В любом веб-приложении допускать выполнение непроверенного, предоставленного пользователем содержимого в виде HTML, CSS или JavaScript потенциально опасно, поэтому по возможности следует избегать этого. Однако бывают случаи, когда некоторый риск может быть допустимым.

Например, такие сервисы, как CodePen и JSFiddle, позволяют выполнять предоставленное пользователем содержимое, но в контексте, где это ожидается, и в некоторой степени "песочницы" внутри iframe. В тех случаях, когда важная функция по своей сути требует определенного уровня уязвимости, ваша команда должна взвесить важность этой функции и худшие сценарии, к которым может привести уязвимость.

HTML-инъекция

Как вы узнали ранее, Vue автоматически экранирует HTML-содержимое, предотвращая случайное внедрение исполняемого HTML в ваше приложение. Однако в случаях, когда вы знаете, что HTML безопасен, вы можете явно экранировать HTML-содержимое:

  • Использование шаблона:

    template
    <div v-html="userProvidedHtml"></div>
  • Использование render-функции:

    js
    h('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:

  1. Разработчик явно просит Vue отображать предоставленный пользователем непроверенный контент в виде шаблонов Vue. Это небезопасно по своей сути, и у Vue нет возможности узнать источник.

  2. Разработчик устанавливает Vue на всю HTML-страницу, которая, как оказалось, содержит серверный рендеринг и пользовательский контент. По сути, это та же проблема, что и №1, но иногда разработчики могут делать это, не осознавая. Это может привести к возможным уязвимостям, когда злоумышленник предоставляет HTML, который безопасен как обычный HTML, но небезопасен как шаблон Vue. Лучшая практика - никогда не устанавливать Vue на узлы, которые могут содержать серверный и пользовательский контент.

Лучшие практики

Общее правило заключается в том, что если вы позволяете выполнять непроверенный, предоставленный пользователем контент (в виде HTML, JavaScript или даже CSS), то вы открываете себя для атак. Это правило справедливо как для Vue, так и для других фреймворков или вообще без них.

Помимо рекомендаций, приведенных выше в отношении потенциальных опасностей, мы также рекомендуем ознакомиться с этими ресурсами:

Затем используйте полученные знания для анализа исходного кода зависимостей на предмет потенциально опасных паттернов, если какие-либо из них включают компоненты сторонних разработчиков или иным образом влияют на то, что выводится в DOM.

Координация работы с бэкендом

Уязвимости безопасности HTTP, такие как подделка межсайтовых запросов (CSRF/XSRF) и межсайтовое включение сценариев (XSSI), в основном решаются на бэкенде, поэтому Vue их не касается. Тем не менее нелишним будет пообщаться с командой бэкенда, чтобы узнать, как лучше взаимодействовать с их API, например, передавать токены CSRF при отправке форм.

Рендеринг на стороне сервера (SSR)

При использовании SSR возникают некоторые дополнительные проблемы с безопасностью, поэтому во избежание уязвимостей обязательно следуйте лучшим практикам, описанным в нашей документации по SSR.

БезопасностьУже загружено