日前Vue项目的github上star数已经18.8W,表明Vue越来越受到开发人员的欢迎。但由于开发人员水平参差不齐,Vue项目所面对的安全问题也日趋严重,以下整理了Vue在编码过程中的最佳安全实践,希望对大家有些帮助
第一原则:永远不要使用不可信任的模板
在使用 Vue 的时候最基本的安全规则是永远不要将不可信任的内容作为模板内容使用。这样做等价于允许在应用程序中执行任意的 JavaScript——甚至更糟的是如果在服务端渲染的话可能导致服务器被攻破。举个例子:
new Vue({
el: '#app',
template: `<div>` + userProvidedString + `</div>` // 永远不要这样做
})
Vue 的模板是被编译为 JavaScript 的,而其中的表达式会作为渲染流程的一部分执行。尽管该表达式是在一个特定的渲染上下文中进行运算的。考虑到潜在的全局运行环境的复杂性,作为类似 Vue 的框架,想要完全让代码远离潜在的恶意代码执行而不导致性能问题,是不切实际的。最直接的回避这类问题的方式就是确保 Vue 模板的内容始终是可信的且完全由你掌控。
Vue 的安全措施
1、HTML 内容
不论使用模板还是渲染函数,内容都会被自动转义。也就是说对于这份模板:
<h1>{{ userProvidedString }}</h1>
如果 userProvidedString 包含了:
'<script>alert("hi")</script>'
则它会被转义成为如下 HTML:
<script>alert("hi")</script>
因此避免了脚本注入。该转义通过诸如 textContent 的浏览器原生的 API 完成,所以除非浏览器本身存在安全漏洞,否则不会存在安全漏洞。
2、Attribute 绑定
同样地,动态 attribute 绑定也会自动被转义。也就是说对于这份模板:
<h1 v-bind:title="userProvidedString">
hello
</h1>
如果 userProvidedString 包含了:
'" onclick="alert('hi')'
则它会被转义成为如下 HTML:
" onclick="alert('hi')
因此避免了通过闭合 title attribute 而注入新的任意 HTML。该转义通过诸如 setAttribute 的浏览器原生的 API 完成,所以除非浏览器本身存在安全漏洞,否则不会存在安全漏洞。
潜在危险
在任何 web 应用中,允许未过滤的用户提供的内容成为 HTML、CSS 或 JavaScript 都有潜在的危险,因此应当尽可能避免。尽管如此,有些情况下的风险是可接受的。
例如,类似 CodePen 和 JSFiddle 这样的服务允许用户提供的内容直接被执行,但这是预期行为,且在 iframe 中以某种程度被隔离在沙箱中。当一些重要功能不可避免地依赖引入一些安全漏洞,您的团队需要自行在该功能的重要性和漏洞带来的最坏场景间进行权衡。
1、注入 HTML
如你之前学到的,Vue 会自动转义 HTML 内容,以避免向应用意外注入可执行的 HTML。然而,某些情况下你清楚这些 HTML 是安全的,这时你可以显式地渲染 HTML 内容:
使用模板:
<div v-html="userProvidedHtml"></div>
使用渲染函数:
h('div', {
domProps: {
innerHTML: this.userProvidedHtml
}
})
使用基于 JSX 的渲染函数:
<div domPropsInnerHTML={this.userProvidedHtml}></div>
注意永远不要认为用户提供的 HTML 是 100% 安全的,除非它是在一个 iframe 沙盒里或者应用中只有编写这些 HTML 的用户可以接触到它。除此之外,允许用户撰写其自己的 Vue 模板会带来类似的危险。
2、注入 URL
在类似这样的 URL 中:
<a v-bind:href="userProvidedUrl">
click me
</a>
如果没有对该 URL 进行“过滤”以防止通过 javascript: 来执行 JavaScript,则会有潜在的安全问题。有一些库如 sanitize-url 可以帮助你做这件事,但请注意:
只要你是在前端进行 URL 过滤,那么就已经有安全问题了。用户提供的 URL 永远需要通过后端在入库之前进行过滤。然后这个问题就会在每个客户端连接该 API 时被阻止,包括原生移动应用。还要注意,甚至对于被过滤过的 URL,Vue 仍无法帮助你保证它们会跳转到安全的目的地。
3、注入样式
来看这个示例:
<a
v-bind:href="sanitizedUrl"
v-bind:style="userProvidedStyles"
>
click me
</a>
让我们假设 sanitizedUrl 已经被过滤过了,所以这已经是一个完全真实的 URL 且没有 JavaScript。但通过 userProvidedStyles,恶意用户仍可以提供 CSS 来进行“点击诈骗”,例如将链接的样式设置为一个透明的方框覆盖在“登录”按钮之上。然后再把 https://user-controlled-website.com/ 做成你的应用的登录页的样子,它们就可能获取一个用户真实的登录信息。
你可以想象到,允许用户为一个<style>
元素提供内容,将产生甚至更严重的安全漏洞,以使得用户完全控制整个页面的样式。这就是为什么 Vue 要在模板内避免渲染 style 标签,例如:
<style>{{ userProvidedStyles }}</style>
为了确保用户完全远离点击诈骗,我们推荐只允许在一个 iframe 沙盒内进行 CSS 的完全控制。或让用户通过一个样式绑定来控制,我们推荐使用其对象语法且只允许用户提供特定的可以安全控制的 property 的值。例如:
<a
v-bind:href="sanitizedUrl"
v-bind:style="{
color: userProvidedColor,
background: userProvidedBackground
}"
>
click me
</a>
4、注入 JavaScript
我们强烈不鼓励使用 Vue 渲染 <script>
元素,因为模板和渲染函数永远不应该产生副作用。然而,这并不是唯一包含可能在运行时会被视为 JavaScript 的字符串。
每个 HTML 元素都有接受 JavaScript 字符串作为其值的 attribute,如 onclick、onfocus 和 onmouseenter。将用户提供的 JavaScript 绑定到它们任意当中都是一个潜在的安全风险,因此应该避免。
请注意,永远不要认为用户提供的 JavaScript 是 100% 安全的,除非它是在一个 iframe 沙盒里或者应用中只有编写该 JavaScript 的用户可以接触到它。
有的时候我们会收到在 Vue 模板中可以产生跨站脚本攻击 (XSS) 的安全漏洞报告。一般情况下,我们不会将这样的案例视为真正的安全漏洞,因为从以下两个可能允许 XSS 的场景看,不存在可行的办法来保护开发者:
开发者显式地要求 Vue 将用户提供的、未经过滤的内容作为 Vue 模板进行渲染。这是无法避免的不安全,Vue 没有办法知道其源头。
开发者向 Vue 挂载包含服务端渲染或用户提供的内容的 HTML 的整个页面。这实质上和问题 #1 是相同的,但是有的时候开发者可能没有意识到。这会使得攻击者提供作为普通 HTML 安全但对于 Vue 模板不安全的 HTML 以导致安全漏洞。最佳实践是永远不要向 Vue 挂载可能包含服务端渲染或用户提供的内容。
最佳实践
通用的规则是只要允许执行未过滤的用户提供的内容 (不论作为 HTML、JavaScript 甚至 CSS),你就可能令自己处于被攻击的境地。这些建议实际上不论使用 Vue 还是别的框架甚至不使用框架,都是成立的。
原文始发于微信公众号(洋洋自语):Vue最佳安全实践
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/272998.html