Безопасность
Отчёт об уязвимостях
Когда поступает сообщение об уязвимости, она сразу же становится нашей главной задачей, и штатный сотрудник бросает все дела, чтобы заняться её устранением. Чтобы сообщить об уязвимости, отправьте сообщение по электронной почте 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("hi")</script>'
то он будет приведен к следующему HTML:
template
<script>alert("hi")</script>
тем самым предотвращая внедрение скрипта. Это экранирование выполняется с помощью собственных API браузера, таких как textContent
, поэтому уязвимость может существовать только в том случае, если уязвим сам браузер.
Привязки атрибутов
Аналогично, динамические привязки атрибутов также автоматически экранируются. Это означает, что в этом шаблоне:
template
<h1 :title="userProvidedString">
hello
</h1>
если содержится userProvidedString
:
js
'" onclick="alert(\'hi\')'
то он будет приведен к следующему HTML:
template
" onclick="alert('hi')
таким образом, предотвращая использование атрибута title
для внедрения нового, произвольного HTML. Это экранирование выполняется с помощью собственных API браузера, таких как setAttribute
, поэтому уязвимость может существовать только в том случае, если уязвим сам браузер.
Потенциальные опасности
В любом веб-приложении допускать выполнение несанированного, предоставленного пользователем содержимого в виде HTML, CSS или JavaScript потенциально опасно, поэтому этого следует избегать, где только возможно. Однако бывают случаи, когда некоторый риск вполне допустим.
Например, такие сервисы, как CodePen и JSFiddle, позволяют выполнять предоставленный пользователем контент, но в контексте, где это ожидается, и в определённой степени «песочницы» внутри iframe. В тех случаях, когда важная функция по своей сути требует определённого уровня уязвимости, ваша команда должна взвесить важность функции и худшие сценарии, к которым приводит уязвимость.
Инъекция HTML
Как вы уже узнали ранее, Vue автоматически экранирует HTML-контент, предотвращая случайное внедрение исполняемого HTML в ваше приложение. Однако в случаях, когда вы знаете, что HTML безопасен, вы можете явно отобразить HTML-контент:
Использование шаблона:
template<div v-html="userProvidedHtml"></div>
Использование рендер-функции:
jsh('div', { innerHTML: this.userProvidedHtml })
Использование рендер-функции в JSX:
jsx<div innerHTML={this.userProvidedHtml}></div>
Предупреждение
Пользовательский HTML никогда не может считаться на 100% безопасным, если только он не находится в песочнице iframe или в той части приложения, где он может быть доступен только пользователю, написавшему этот HTML. Кроме того, разрешение пользователям писать собственные шаблоны Vue таит в себе аналогичные опасности.
Инъекция URL
В таком URL-адресе:
template
<a :href="userProvidedUrl">
click me
</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
}"
>
click me
</a>
Инъекция JavaScript
Мы настоятельно рекомендуем никогда не рендерить элемент <script>
во Vue, поскольку шаблоны и рендер-функции никогда не должны иметь побочных эффектов. Однако это не единственный способ включить строки, которые во время выполнения будут анализироваться как 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, чтобы избежать уязвимостей.