关于前端安全性那些事
前言
这篇文章鸽了好久了,一直在草稿箱呆着,刚好这周在家休病假,终于有时间更了。
为啥突然想写前端安全性相关的文章了呢?
起因是在逛boss直聘或者前程无忧等提桶软件时,看到很多职位要求都写了精通前端安全性相关问题,我:黑人问号脸.jpg!现在什么都要精通了嘛?
那么前端相关的安全性问题都有哪些呢?
1、XSS攻击
提起前端安全性问题,我第一个想起来的就是XSS( 全称为Cross Site Scripting,为了和CSS分开简写为XSS,也就是跨站脚本注入)。指攻击者在 html 中嵌入script,浏览器遇到 html 中的 script 标签时,会解析并执行其中的js代码,攻击者直接为所欲为。
XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行
那么问题来了,他怎么在我的html中嵌入代码呢?举个栗子,在三大框架没有出来之前,我们渲染一般通过数据拼接html,然后使用 innerHtml、outerHTML、document.write 的方式,往页面中动态添加渲染元素,假如页面有个查询功能,点击查询按钮后,url会拼接用户输入的 search key,那么攻击者可以通过直接修改url拼接的key为,当用户点了这个改造过的url后,查询的key复显,碰巧你没有对用户输入的数据做转义,浏览器遇到 script 标签就会直接执行 alert。这只是xss攻击最简单的一种方式。
不过现在三大框架已经不需要我们通过上述的方式渲染数据了,再加上模板语法渲染时做了处理,已经很大程度上帮我们避免了这种攻击方式。
除此之外还有很多方式可以注入,美团技术团队分享的 这篇文章 总结的非常好,XSS攻击被分为存储型、反射型和 DOM型三种。
1.1、存储型
存储型就是攻击者将恶意代码提交到目标网站的数据库中,当用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器,用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
预防这种漏洞,有两种常见做法:
- 纯前端渲染,代码和数据分离,比如vue等框架。
- 对HTML做充分转义,如果拼接html是必须的(比如需要做SEO优化),那么需要对HTML各个插入点进行充分的转义,常用的模板引擎,如 doT.js、ejs、FreeMarker 等。
1.2、反射型
反射型 XSS 的攻击步骤:
攻击者构造出特殊的 URL,其中包含恶意代码。
用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。是不是感觉很熟悉,我们找盗版资源时候,那些网站上那些性感游戏图片??
1.3、DOM型
DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。 与存储型比较类似,唯一的区别就是DOM型不用通过数据库,也就是开篇时最上面讲的那种,通过serch input 进行注入。
如何预防:
- 如果用 Vue/React 技术栈,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTML、outerHTML 的 XSS 隐患。
- 尽量不使用 .innerHTML、.outerHTML、document.write()等方法,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent、.setAttribute() 等。
- location、onclick、onerror、onload、onmouseover 等, 标签的 href 属性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串作为代码运行。尽量避免把不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患。
通用的预防方案: Content Security Policy
严格的 CSP 在 XSS 的防范中可以起到以下的作用:
- 禁止加载外域代码,防止复杂的攻击逻辑。
- 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
- 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
- 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
2、 Iframe 2.1、让自己的网站不被其他网站的 iframe 引用
通过判断location,如果不是自己的网站则重定向到其他网站,可以是无法访问的页面,也可以直接给他跳转到百度、谷歌等。
1 2 3 |
|
2.2 、禁用使用iframe内嵌页面操作自己网站
通过h5的新特性 Sandbox
1 2 3 |
|
可选值如下:
allow-forms
允许嵌入式浏览上下文提交表单。如果未使用此关键字,则不允许此操作。allow-modals
允许嵌入式浏览上下文打开模态窗口。allow-orientation-lock
允许嵌入式浏览上下文禁用锁定屏幕方向的功能。allow-pointer-lock
允许嵌入式浏览上下文使用Pointer Lock API (en-US)。allow-popups
允许弹出窗口(像window.open,target=“_blank”,showModalDialog)。如果未使用此关键字,则该功能将无提示失败。allow-popups-to-escape-sandbox
允许沙盒文档打开新窗口而不强制沙盒标记。例如,这将允许安全地沙箱化第三方广告,而不会对登陆页面施加相同的限制。allow-presentation
允许嵌入器控制 iframe 是否可以启动演示会话。allow-same-origin
允许将内容视为来自其正常来源。如果未使用此关键字,则嵌入的内容将被视为来自唯一来源。allow-scripts
允许嵌入式浏览上下文运行脚本(但不创建弹出窗口)。如果未使用此关键字,则不允许此操作。allow-top-navigation
允许嵌入式浏览上下文将内容导航(加载)到顶级浏览上下文。如果未使用此关键字,则不允许此操作。
2.3、 打开新标签跳转 window.opener
我们常用的打开新标签页的方式通常有两种
1 2 |
|
1 |
|
考虑以下场景:
A 页面通过 或 window.open 方式,打开 B 页面。但是 B 页面存在恶意代码如下:
1 2 |
|
此时,用户正在浏览新标签页,但是原来网站的标签页已经被导航到了百度页面。甚至恶意网站可以伪造一个足以欺骗用户的页面,从而获得用户的敏感信息。即使在跨域状态下 opener 仍可以调用 location.replace 方法。
对于a标签,我们可以采用配置rel属性的方式解决此问题:
1 2 |
|
对于window.open,可采用手动置空的方式解决此问题:
1 2 3 |
|
3、跨站请求伪造(Cross-site request forgery)
wiki百科的解释是这样的:
跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求是发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
wiki举的例子:
假如一家银行用以执行转账操作的URL地址如下: https://bank.example.com/withdraw?account=AccoutName;amount=1000;for=PayeeName
那么,一个恶意攻击者可以在另一个网站上放置如下代码:
如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。
这种恶意的网址可以有很多种形式,藏身于网页中的许多地方。此外,攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着如果服务端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险。
防御措施(推荐添加token / HTTP头自定义属性):
- HTTP 协议中使用 Referer 属性来确定请求来源进行过滤
HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址。在处理敏感数据请求时,通常来说,Referer字段应和请求的地址位于同一域名下。以上文银行操作为例,Referer字段地址通常应该是转账按钮所在的网页地址,应该也位于bank.example.com之下。而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,不会位于bank.example.com之下,这时候服务器就能识别出恶意的访问。
- 请求地址添加 token ,使黑客无法伪造用户请求
- HTTP 头自定义属性验证(类似上一条)
- Cookie-SameSite属性
Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。它可以设置三个值。
Strict完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外(只包括三种情况:链接,预加载请求,GET 表单)。
None 关闭SameSite。
还记得浏览器的同源策略吗,也就是跨域访问限制,同源策略确实减少了部分CSRF发生,但并不能完全解决该问题。
4、ClickJacking(点击劫持)
一般会利用透明 iframe 覆盖原网页诱导用户进行某些操作达成目的。
原理非常简单
访问者被恶意页面吸引。怎样吸引的不重要。
页面上有一个看起来很诱人的图片(例如:点我,超好玩!或者美女秘书等你来体验!”)。
恶意页面在该链接上方放置了一个透明的