vue2.x学习笔记(三十一)
接着前面的内容:https://www.cnblogs.com/yanggb/p/12683075.html。
安全
现在的企业都比较在意信息系统的安全问题,在使用vue的过程中也要注意这一点。
报告安全漏洞
官方承诺,当收到一个安全漏洞报告,将给予其最高优先级,并由全职贡献者停下手中的工作处理此事(可以将发现的安全漏洞通过邮件给security@vuejs.org的形式反馈给官方)。虽然发现新安全漏洞是比较罕见的事情,但是官方仍然是推荐始终使用最新版本的vue及其官方的周边库,以确保应用尽可能安全。
安全的第一原则:用于不要使用不可信任的模板
在使用vue的时候最基本的安全规则是永远不要将不可信任的内容作为模板内容使用,因为这样做等价于允许在应用程序中执行任意的javascript一样,前端逻辑可能会因此被恶意破坏。甚至更糟糕的是如果在服务器渲染的话可能导致服务器被攻破。
new Vue({ el: '#app', template: `<div>` + userProvidedString + `</div>` // 永远不要这样做 })
因为vue的模板是最终被编译称为javascript的,而其中的表达式会作为渲染流程的一部分执行。尽管该表达式是在一个特定的渲染上下文中进行运算的。考虑到潜在的全局运行环境的复杂性,作为类似vue的框架,想要完全让代码远离潜在的恶意代码行而不导致性能问题,是不切实际的。最直接的回避这类问题的方法,就是确保vue模板的内容始终是可信的,且是完全由你掌控的。
vue中的安全措施-html内容
不论使用模板还是渲染函数,内容都会被自动转义。也就是说,对于以下这份模板:
<h1>{{ userProvidedString }}</h1>
如果userProvidedString包含了:
'<script>alert("hi")</script>'
它就会被转义为以下的html:
<script>alert("hi")</script>
这样就在一定程度上避免了脚本注入,因为浏览器最终识别的内容不再是脚本,而是普通的文本。该转义是通过诸如textContent的浏览器原生api完成的,除非浏览器本身存在安全漏洞,否则是不会存在安全漏洞的。
vue中的安全措施-attribute绑定
同样的,动态的attribute绑定也会被自动转义。也就是说,对于以下这份模板:
<h1 v-bind:title="userProvidedString"> hello </h1>
如果在userProvidedString中包含了:
'" onclick="alert(\'hi\')'
其就会被自动转义为以下的html:
" onclick="alert('hi')
这样就有效避免了通过闭合title属性而注入新的任意html。该转义是通过诸如textContent的浏览器原生api完成的,除非浏览器本身存在安全漏洞,否则是不会存在安全漏洞的。
潜在危险
在任何的web应用中,允许未过滤的用户提供的内容称为html、css或javascript都有潜在的危险,因此应当尽可能避免。尽管如此,有些情况下的风险是可接受的。
例如,类似Code和JSFiddle这样的服务就允许用户提供的内容直接被执行。但这是预期行为,且在iframe中以某种程度被隔离在沙箱中。当一些重要功能不可避免地依赖引入一些安全漏洞的时候,你的开发团队就需要自行在该功能的重要性和漏洞带来的最坏场景之间进行权衡。
注入html
如上面说到的,vue会自动转义html的内容,以此来避免向应用意外注入可执行的html。然而在一些场景中,你可能会很清楚这些html是安全的,这时你就可以显式地渲染html内容。
1.使用模板(v-html):
<div v-html="userProvidedHtml"></div>
2.使用渲染函数(render):
h('div', { domProps: { innerHTML: this.userProvidedHtml } })
3.使用基于jsx的渲染函数:
<div domPropsInnerHTML={this.userProvidedHtml}></div>
注意,永远不要认为用户提供的html是100%安全的,除非它是在一个iframe沙盒里或者应用中只有编写这些html的用户可以接触到它。除此之外,允许用户撰写其自己的vue模板会带来类似的危险。
注入url
在类似这样的url中:
<a v-bind:href="userProvidedUrl"> click me </a>
如果没有对该url进行过滤以防止通过【javascript:】来执行javascript,则会有潜在的安全问题。有一些库,比如sanitize-url可以帮助你做这件事,但是请注意:只要你只是在前端进行了url过滤,那么就已经有了安全问题了。用户提供的url永远需要通过后端在入库之前进行过滤,然后这个问题就会在每个客户端连接该api的时候被阻止,包括原生的移动应用。此外还要注意,甚至对于被过滤的url,vue仍然无法帮助开发者保证它们会跳转到安全的目的地。
注入样式
来看这个示例:
<a v-bind:href="sanitizedUrl" v-bind:style="userProvidedStyles"> click me </a>
我们先假设sanitizedUrl已经被过滤过了,所以这已经是一个完全真实的url且没有javascript。但通过userProvidedStyles,恶意用户仍然可以提供css来进行【点击诈骗】,例如将链接的样式设置为一个透明的方框覆盖在登录按钮之上,然后再把登录的地址做成你的应用的登录页的样子(假冒),它们就可能获取一个用户真实的登录信息(账号密码等)。
你可以想象到,允许一个用户为一个<style>元素提供内容,将产生甚至更严重的安全漏洞,比如上面的例子就可能会导致网站用户隐私信息被泄露的严重问题。这也是为什么vue在模板内避免渲染style标签的原因,例如:
<style>{{ userProvidedStyles }}</style>
为了确保用户完全远离【点击诈骗】,官方文档推荐只允许在一个iframe沙盒内进行css的完全控制。或让用户通过一个样式绑定来控制,我们推荐使用其对象语法且只允许用户提供特定的、可以安全控制的property的值,例如:
<a v-bind:href="sanitizedUrl" v-bind:style="{ color: userProvidedColor, background: userProvidedBackground }"> click me </a>
这样,不符合css属性格式的值将会被直接抛弃,很大程度上避免了css注入的问题。
注入javascript
官方强烈不推荐使用vue渲染<script>元素,因为模板和渲染函数永远不应该产生副作用。然而,这并不是唯一包含可能在运行时会被视为javascript的字符串。
每个html元素都有接受javascript字符串作为其值的attribute,如onclick、onfocus和onmouseenter。将用户提供的javascript绑定到它们任意当中都是一个潜在的安全风险,因此应该避免。
请注意,永远不要认为用户提供的javascript是100%安全的,除非它是在一个iframe沙盒里或者应用中只有编写该javascript的用户可以接触到它。
有的时候我们会收到在vue模板中可以产生跨站脚本攻击(XSS)的安全漏洞报告。一般情况下,我们不会将这样的案例视为真正的安全漏洞,因为从以下两个可能允许CSS的场景来看,不存在可行的办法来保护开发者:
1.开发者显式地要求vue将用户提供地、未经过过滤的内容作为vue模板进行渲染。这是无法避免的不安全,因为vue没有办法知道其源头。
2.开发者向vue挂载包含服务端渲染或用户提供的内容的html的整个页面。这实际上和问题1是相同的,但是有的时候开发者可能没有意识到。这会使得攻击者提供作为普通html安全但对于vue模板不安全的html以导致安全漏洞。最佳实践是永远不要向vue挂载可能包含服务端渲染或用户提供的内容。
最佳实践
通用的规则是只要允许执行未过滤的用户提供的内容(不论作为html,javascript甚至css),你就可能令自己出于被攻击的境地。这些建议实际上不论使用vue还是别的框架,甚至不使用框架,都是成立的。
除了上述关于潜在危险的建议,官方文档还推荐自行熟悉以下资料:
然后利用学到的知识,对那些包含了第三方组件或通过其他方式影响渲染到dom的内容的依赖的源代码进行重新审查,以发现潜在的危险模式。
后端协作
http安全漏洞,诸如伪造跨站请求(CSRF/XSRF)和跨站脚本注入(XSSI),都是后端重点关注的方向,因此并不是vue所担心的。尽管如此,和后端团队交流学习任何和他们的api最好地进行交互,例如在表单提交的时候提交CSRF token,永远是一件好事。
服务端渲染(SSR)
使用SSR时存在额外的安全考量,因此需要开发者确认遵循官方的 SSR 文档中概括出的最佳实践,以避免安全漏洞的产生。
"我还是很喜欢你,像春风守护着晨曦,不曾远去。"