前端安全系列(一):如何防止XSS攻击?
参考链接:https://www.cnblogs.com/unclekeith/p/7750681.html 、https://www.freebuf.com/articles/web/185654.html
详细描述XSS过程:https://www.cnblogs.com/caizhenbo/p/6836390.html
XSS定义
XSS, 即为(Cross Site Scripting), 中文名为跨站脚本, 是发生在目标用户的浏览器层面上的,当渲染DOM树的过程成发生了不在预期内执行的JS代码时,就发生了XSS攻击。
跨站脚本的重点不在‘跨站’上,而在于‘脚本’上。大多数XSS攻击的主要方式是嵌入一段远程或者第三方域上的JS代码。实际上是在目标网站的作用域下执行了这段js代码。
XSS 的本质是:
- 恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。在部分情况下,由于输入的限制,注入的恶意脚本比较短。但可以通过引入外部的脚本,并由浏览器执行,来完成比较复杂的攻击策略。
XSS危害
- 通过document.cookie盗取cookie
- 使用js或css破坏页面正常的结构与样式
- 流量劫持(通过访问某段具有window.location.href定位到其他页面
- Dos攻击:利用合理的客户端请求来占用过多的服务器资源,从而使合法用户无法得到服务器响应。
- 利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。
- 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。
对cookie的保护
- 对重要的cookie设置httpOnly, 防止客户端通过document.cookie读取cookie。服务端可以设置此字段。
防御总结
- XSS 一般利用js脚步读取用户浏览器中的Cookie,而如果在服务器端对 Cookie 设置了HttpOnly 属性,那么js脚本就不能读取到cookie,但是浏览器还是能够正常使用cookie。一般的Cookie都是从document对象中获得的,现在浏览器在设置 Cookie的时候一般都接受一个叫做HttpOnly的参数,跟domain等其他参数一样,一旦这个HttpOnly被设置,你在浏览器的 document对象中就看不到Cookie了,而浏览器在浏览的时候不受任何影响,因为Cookie会被放在浏览器头中发送出去(包括ajax的时 候),应用程序也一般不会在js里操作这些敏感Cookie的,对于一些敏感的Cookie我们采用HttpOnly,对于一些需要在应用程序中用js操作的cookie我们就不予设置,这样就保障了Cookie信息的安全也保证了应用。
- 对输入和URL参数进行过滤:如将容易引起xss漏洞的半角字符直接替换成全角字符
过滤常见危险的标签:
if (tag === 'script' || tag === 'img' || tag === 'link' || tag === 'style' || tag === 'iframe' || tag === 'frame') return
- 对输出进行编码:在输出数据之前对潜在的威胁的字符进行编码、转义是防御XSS攻击十分有效的措施。
一个案例
某天,公司需要一个搜索页面,根据 URL 参数决定关键词的内容。小明很快把页面写好并且上线。代码如下:
< input type = "text" value = "<%= getParameter(" keyword ") %> ">
< button > 搜索 </ button >
< div >
您搜索的关键词是: < %= getParameter (" keyword ") %>
</ div >
然而,在上线后不久,小明就接到了安全组发来的一个神秘链接:
小明带着一种不祥的预感点开了这个链接 [请勿模仿,确认安全的链接才能点开] 。果然,页面中弹出了写着”XSS”的对话框。
可恶,中招了!小明眉头一皱,发现了其中的奥秘:
当浏览器请求 http://xxx/search?keyword=">,拼接到 HTML 中返回给浏览器。形成了如下的 HTML:
< input type = "text" value = "" > < script > alert( 'XSS' ); </ script > ">
< button > 搜索 </ button >
< div >
您搜索的关键词是:"> < script > alert( 'XSS' ); </ script >
</ div >
浏览器无法分辨出 是恶意代码,因而将其执行。
这里不仅仅 div 的内容被注入了,而且 input 的 value 属性也被注入, alert 会弹出两次。
面对这种情况,我们应该如何进行防范呢?
其实,这只是浏览器把用户的输入当成了脚本进行了执行。那么只要告诉浏览器这段内容是文本就可以了。
聪明的小明很快找到解决方法,把这个漏洞修复:
< input type = "text" value = "<%= escapeHTML(getParameter(" keyword ")) %> ">
< button > 搜索 </ button >
< div >
您搜索的关键词是: < %= escapeHTML ( getParameter (" keyword ")) %>
</ div >
escapeHTML() 按照如下规则进行转义:
字符 | 转义后的字符 |
---|---|
& | & |
< | < |
> | > |
" | " |
’ | ' |
/ | / |
经过了转义函数的处理后,最终浏览器接收到的响应为:
< input type = "text" value = ""><script>alert('XSS');</script>" >
< button > 搜索 </ button >
< div >
您搜索的关键词是:"><script>alert('XSS');</script>
</ div >
恶意代码都被转义,不再被浏览器执行,而且搜索词能够完美的在页面显示出来。
通过这个事件,小明学习到了如下知识:
通常页面中包含的用户输入内容都在固定的容器或者属性内,以文本的形式展示。
攻击者利用这些页面的用户输入片段,拼接特殊格式的字符串,突破原有位置的限制,形成了代码片段。
攻击者通过在目标网站上注入脚本,使之在用户的浏览器上运行,从而引发潜在风险。
通过 HTML 转义,可以防止 XSS 攻击。 [事情当然没有这么简单啦!请继续往下看] 。
自从上次事件之后,小明会小心的把插入到页面中的数据进行转义。而且他还发现了大部分模板都带有的转义配置,让所有插入到页面中的数据都默认进行转义。这样就不怕不小心漏掉未转义的变量啦,于是小明的工作又渐渐变得轻松起来。
还有其他几种攻击,参考:https://www.freebuf.com/articles/web/185654.html
小明的例子讲完了,下面我们来系统的看下 XSS 有哪些注入的方法:
在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。
在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。
在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。
在标签的 href、src 等属性中,包含 javascript: 等可执行代码。
在 onload、onerror、onclick 等事件中,注入不受控制代码。
在 style 属性和标签中,包含类似 background-image:url(“javascript:…”);的代码(新版本浏览器已经可以防范)。在 style 属性和标签中,包含类似 expression(…) 的 CSS 表达式代码(新版本浏览器已经可以防范)。
总之,==如果开发者没有将用户输入的文本进行合适的过滤,就贸然插入到 HTML 中,这很容易造成注入漏洞。==攻击者可以利用漏洞,构造出恶意的代码指令,进而利用恶意代码危害数据安全。
【@tx笔记】补充:
上面的不全面!!
https://xz.aliyun.com/t/1672
XSS反射性防护:
- 输入转义
- 设置安全的HTTP头字段:
- X-XSS-Protection: 1; mode=block
- Internet Explorer,Chrome和Safari的一个功能,当检测到跨站脚本攻击 (XSS)时,浏览器将停止加载页面
- X-Content-Type-Options: nosniff
- 下面两种情况的请求将被阻止:
请求类型是"style" 但是 MIME 类型不是 “text/css”,
请求类型是"script" 但是 MIME 类型不是)
- 下面两种情况的请求将被阻止:
- X-XSS-Protection: 1; mode=block
前端安全系列(二):CSRF
定义
- CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
- hack利用用户登录状态操作隐私或者敏感功能。
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
hack主要是利用cookie的信息
1.get请求尽量不要用
2.加入智能复杂的验证码
参考:https://blog.csdn.net/qq_38089964/article/details/80803415
由于前端的标签的src属性支持bese64编码的图片源,所以后台可以将生成的验证码以base64编码形式传给前台进行展示,同时将验证码的内容一起传给前台,考虑到安全性的问题,可以将验证码的内容也经过base64编码,这样每次验证请求的时候就可以对用户输入的验证码进行base64编码之后比对验证。
3.http 头header里面有referer,可以记录当前请求的来源地址,若不是该网站,则直接拒绝。【在特定的,例如转账借口上加拦截器,检查referer,但并不是完全完全的】
4.【常用,关键在token的保密性和随机性!】①服务端产生token,随机产生的、②服务端把token放在放到session里面或MySQL的缓存中?,
③客户端可把token放在区域或者表单中,可用js提取,在post请求时把token带给服务端
④每次请求过来,服务端就要验证,且验证通过后要销毁,否咋被hack拿走
参考链接:https://www.jianshu.com/p/7d6331b7fa29
第二种方法大都是通过在form中填充隐藏的csrf_token。这种方法适用于服务器端渲染的页面,对于前后端分离的情况就不太适用了。针对前后端分离情况,我有两种方法:
(1).Cookie-to-header token
登录的时候,服务器生成一个随机的csrf_token,放入cookie中,同时在session中也存一份。
Set-Cookie: Csrf-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=/
浏览器通过JavaScript读取cookie中的Csrf_token,然后在发送请求时作为自定义HTTP头发送回来。
X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
服务器读取HTTP头中的Csrf_token,与session中的Csrf_token比较,一致则放行,否则拒绝。
这种方法为什么能够防御CSRF攻击呢?
关键在于JavaScript读取cookie中的Csrf_token这步。由于浏览器的同源策略,攻击者是无法从被攻击者的cookie中读取任何东西的。所以,攻击者无法成功发起CSRF攻击。
(2).JWT(Json Web Token)
5.自定义header