安全性
报告漏洞
当报告漏洞时,它立即成为我们的首要关注事项,一个全职贡献者会放下一切来处理它。为了报告漏洞,请发送电子邮件至 [email protected]。
尽管发现新的漏洞很少,但我们也建议始终使用Vue及其官方配套库的最新版本,以确保您的应用程序尽可能安全。
规则第1条:绝不要使用不可信的模板
使用Vue时的最基本安全规则是 绝不要将不可信内容用作组件模板。这样做等同于允许在您的应用程序中执行任意JavaScript - 更糟糕的是,如果在服务器端渲染期间执行代码,可能会导致服务器泄露。此类使用的示例
js
Vue.createApp({
template: `<div>` + userProvidedString + `</div>` // NEVER DO THIS
}).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
,因此只有当浏览器本身存在漏洞时,才可能存在漏洞。
潜在危险
在任何Web应用程序中,允许未经过滤的用户提供的内谷作为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在沙盒化的iframe中或仅在编写该HTML的用户可能接触到的应用程序部分中,否则用户提供的HTML永远不能被认为是100%安全的。此外,允许用户编写自己的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"
>
click me
</a>
假设 sanitizedUrl
已经被净化,所以它肯定是一个真实的URL而不是JavaScript。有了 userProvidedStyles
,恶意用户仍然可以提供CSS来“点击劫持”,例如将链接样式设置为透明的框覆盖在“登录”按钮上。然后如果 https://user-controlled-website.com/
被构建得与您的应用程序的登录页面相似,他们可能已经捕获了用户的真实登录信息。
您可能能够想象,允许用户为 <style>
元素提供内容将会如何创建更大的安全漏洞,因为这会让用户完全控制整个页面的样式。这就是为什么 Vue 阻止在模板中渲染样式标签,例如
template
<style>{{ userProvidedStyles }}</style>
为了确保您的用户完全免受点击劫持,我们建议只允许在沙盒 iframe 内对 CSS 完全控制。或者,当通过样式绑定提供用户控制时,我们建议使用其 对象语法,并且只允许用户为它们可以安全控制的特定属性提供值,如下所示
template
<a
:href="sanitizedUrl"
:style="{
color: userProvidedColor,
background: userProvidedBackground
}"
>
click me
</a>
JavaScript 注入
我们强烈建议永远不要使用 Vue 渲染 <script>
元素,因为模板和渲染函数永远不应该有副作用。然而,这并不是唯一一种在运行时将其评估为 JavaScript 的字符串的方法。
每个 HTML 元素都有接受字符串的属性值,例如 onclick
、onfocus
和 onmouseenter
。将用户提供的 JavaScript 绑定到任何这些事件属性上是一种潜在的安全风险,因此应该避免。
警告
除非它位于沙盒 iframe 中或在应用中只有编写该 JavaScript 的用户才能暴露于其中,否则用户提供的 JavaScript 永远不能被认为是 100% 安全的。
有时我们会收到关于如何在 Vue 模板中执行跨站脚本(XSS)的漏洞报告。一般来说,我们不认为这些情况是真正的漏洞,因为没有实际的方法可以保护开发者免受允许 XSS 的两种场景。
开发者明确要求 Vue 将用户提供的未经过滤的内容作为 Vue 模板进行渲染。这是固有的不安全行为,Vue 无法知道其来源。
开发者将 Vue 安装在一个包含服务器端渲染和用户提供内容的整个 HTML 页面上。这与 #1 基本上是同一个问题,但有时开发者可能没有意识到这一点。这可能导致攻击者提供作为纯 HTML 安全但作为 Vue 模板不安全的 HTML。最佳实践是 永远不要在可能包含服务器端渲染和用户提供内容的节点上安装 Vue。
最佳实践
一般规则是,如果您允许未经过滤的用户提供的内容被执行(无论是作为 HTML、JavaScript 还是 CSS),您可能使自己容易受到攻击。无论使用 Vue、其他框架,还是根本不使用框架,这些建议实际上都是正确的。
除了上述 潜在危险 的建议外,我们还建议您熟悉这些资源
然后使用您学到的知识来审查您的依赖项的源代码,以寻找潜在的危险模式,如果其中任何包含第三方组件或以其他方式影响渲染到 DOM 的内容。
后端协调
HTTP安全漏洞,如跨站请求伪造(CSRF/XSRF)和跨站脚本包含(XSSI),主要在后端解决,因此它们不是Vue的关注点。然而,与您的后端团队沟通以了解如何最好地与他们交互仍然是一个好主意,例如,通过在表单提交中提交CSRF令牌。
服务器端渲染(SSR)
使用SSR时,还有一些额外的安全关注点,因此请确保遵循我们在我们的SSR文档中概述的最佳实践,以避免漏洞。