转载请注明出处:unclekeith: 前端安全之CSRF攻击html
CSRF,即(Cross-site request forgery), 中文名为跨站请求伪造。是一种挟持用户在当前已登陆的Web应用程序上执行非本意的操做的一种攻击方式。CSRF攻击的本质在于利用用户的身份,执行非本意的操做。根据CSRF的全名,能够得出的结论是:CSRF的请求是跨域且伪造的。前端
跨域指的是请求来源于其余网站。好比说,目标网站上的删除文章功能接收到来自其余网站的删除文章的请求,那么这个请求就是跨域的。web
伪造指的是若是这个请求不是用户自身的意愿,那么这个请求就是伪造的。跨域
简单的说,跨站请求伪造的攻击是攻击者经过一些技术手段欺骗用户的浏览器去访问用户曾经认证过的网站并执行一些操做(如发送邮件、发消息、甚至财产操做如转帐和购买商品等)。因为浏览器曾经认证过,因此被访问的网站会认为是真正的用户操做而去执行。这利用了web登陆身份认证的一个漏洞:简单的身份认证只能保证请求来自用户的浏览器,但不能识别请求是用户自愿发出的。浏览器
假若有这么一个场景,目标网站A的url:www.a.com。恶意网站B的url:www.b.com。安全
GET CSRF:
两个网站的域名不同,目标网站A上有一个删除文章的功能,一般是用户单击’删除文章‘连接时才会删除指定的文章。这个连接是www.a.com/blog/del?id=1, id表明不一样的文章。实际上就是发起一个GET请求。服务器
若是在目标网站A上存在XSS漏洞,那么能够利用这个XSS漏洞来进行攻击。注意,XSS攻击是在用户的浏览器上进行的。若是对XSS攻击不熟悉的朋友,能够看看这篇文章。传送门:前端安全之XSS攻击cookie
1. 使用Ajax发起一个GET请求,由于是在目标网站上,因此符合同源策略。请求参数为id=1, 请求目标地址为www.a.com/blog/del。 2. 或者在目标网站A上动态建立一个标签(script, img, iframe等),将其src指向www.a.com/blog/del?id=1, 那么攻击就会发起。实际上经过这种方式发起的请求就是一个GET请求。 3. 最后欺骗用户登陆目标网站A,那么攻击就会发生。
若是在目标网站A上不存在XSS漏洞,那么能够利用GET CSRF进行攻击app
1. 没法使用Ajax发起GET请求。由于CSRF请求是跨域的,而Ajax有同源策略的限制。 2. 能够经过在恶意网站B上静态或者动态建立img,script等标签发起GET请求。将其src属性指向www.a.com/blog/del?id=1。经过标签的方式发起的请求不受同源策略的限制。 3. 最后欺骗已经登陆目标网站A的用户访问恶意网站B,那么攻击就会发生。此时恶意网站B的请求是身份认证后的。
对比CSRF和XSS攻击能够看出,CSRF攻击有如下几个关键点网站
恶意网站B发出的删除文章的GET请求的请求头
GET /blog/del?id=1 HTTP/1.1 Host: www.a.com * Referer: http://www.b.com/csrf.html Connection: Keep-Alive Cookie: name=kk Other-Request-Name: Other-Request-Value:
目标网站A发出的删除文章的GET请求的请求头
GET /blog/del?id=1 HTTP/1.1 Host: www.a.com * Referer: http://www.a.com/blog/ Connection: Keep-Alive Cookie: name=kk Other-Request-Name: Other-Request-Value:
对比以上的代码能够看出,只有Referer字段不一样。也就是说,只有请求来源不相同,而发送删除文章的请求时都会带上相同的cookie信息。这样的请求就是身份认证后的,CSRF攻击就会成功。
POST CSRF:POST请求实际上就是在恶意网站B上发起一个POST请求,一样的,这个请求也是跨域和身份认证后的。如静态或动态的建立一个form表单,当用户访问到这个恶意网站B时,就会提交这个表单。
假如目标网站A上有‘写文章’的功能,那么咱们就能够动态建立form标签,而后修改文章的题目。
www.b.com/csrf.html function setForm () { var form = document.createElement('form') form.action = 'www.a.com/blog/article' form.methods = 'POST' var input = document.createElement('input') input.type = 'text' input.value = 'csfr攻击啦!' input.id = 'title' form.appendChild(input) document.body.appendChild(form) form.submit() } setForm()
上面代码能够看出,动态建立了form表单,而后调用submit方法。就能够经过跨域的伪造请求来实现修改目标网站A的某篇文章的标题了。
以上说了GET和POST的CSRF攻击。本质上都是欺骗用户以本身的身份去执行非本意的操做。欺骗流程大体以下
1. 首先欺骗用户登陆目标网站。 2. 而后欺骗用户登陆恶意网站。这种恶意的网站有不少种形式,藏身于网页中的许多地方。此外,攻击者也不须要控制放置恶意网址的网站。例如他能够将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着若是服务器端没有合适的防护措施的话,用户即便访问熟悉的可信网站也有受攻击的危险。
从GET CSRF例子中能够看到,目标网站A和恶意网站B发出的请求中,请求头惟一的不一样就是Referer字段。一般来讲,Referer字段一般与Host字段的域名是同样的。
以上面删除文章功能为例,在目标网站A中的Referer字段为http://www.a.com/blog/
,而恶意网站B中的Referer字段为http://www.b.com/csrf.html
。因此根据Referer字段与Host字段在同一域名下的规则,能够检测Referer字段值,若是发现其与Host值不在同一域名下,这时候服务器就可以识别出恶意的访问了。
因为CSRF的本质在于攻击者欺骗用户去访问本身设置的地址,因此若是要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,而且攻击者没法伪造的数据做为校验,那么攻击者就没法再执行CSRF攻击。这种数据一般是表单中的一个数据项。服务器将其生成并附加在表单中,其内容是一个随机数。即<input type="hidden" name="_csrf_token" value="xxxx">)
的形式。
当客户端经过表单提交请求时,这个随机数也一并提交上去以供校验。正常的访问时,客户端浏览器可以正确获得并传回这个随机数,而经过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个随机数的值,服务器端就会由于校验token的值为空或者错误,拒绝这个可疑请求。
为了防范CSRF,在须要增删改数据时,使用POST请求,而不要使用GET请求。
具体的方案以下:
1. 服务端在收到客户端请求时,生成一个随机数,在渲染页面时将随机数埋入页面(通常埋入form表单中),<input type="hidden" name="_csrf_token" value="xxxx">)`的形式。每次刷新页面后这个随机数都会改变,并在服务器中存储。 2. 服务端设置Set-Cookie, 把该随机数做为cookie种入用户浏览器。 3. 当用户发送GET或POST请求时带上_csrf_token参数(对于form表单直接提交便可) 4. 后台在接受到请求后解析请求头中的cookie字段,获取_csrf_token的值,而后和用户请求提交的_csrf_token值作比较。若是相等则表示请求来源是合法的。
参考资料:
1.《web前端黑客技术》
2.聊聊CSRF