Безопасность
Вакансии vuejobs.com
Сообщение об уязвимостях
Когда поступает сообщение об уязвимости, оно сразу же становится нашей главной задачей, и штатный сотрудник бросает все дела, чтобы заняться ее устранением. Чтобы сообщить об уязвимости, напишите, пожалуйста, по адресу 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>
Чтобы полностью обезопасить пользователей от "щелчков", мы рекомендуем предоставлять полный контроль над 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.