文章内容为转载整理。
转载原文地址: https://www.jianshu.com/p/7f33f9c7997b https://www.jianshu.com/p/25a9fec92be8 http://www.cnblogs.com/hyddd/CSRF(Cross-site request forgery)跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
CSRF 攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下执行在权限保护之下的操作。通俗理解为:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
【图片转自:https://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html】
从上图可以看出,要完成一次CSRF的攻击,受害者必须依次完成两个步骤:
1:登录受信任网站A,并在本地生成cookie。
2:在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
这种类型的CSRF一般是由于程序员安全意识不强造成的。GET类型的CSRF利用非常简单,只需要一个HTTP请求,所以,一般会这样利用:
<img src=http://wooyun.org/csrf?xx=11 />在访问含有这个img的页面后,成功向http://wooyun.org/csrf?xx=11发出了一次HTTP请求。所以,如果将该网址替换为存在GET型CSRF的地址,就能完成攻击了。
这种类型的CSRF危害没有GET型的大,利用起来通常使用的是一个自动提交的表单,如:
<form action=http://wooyun.org/csrf.php method=POST> <input type="text" name="xx" value="11" /> </form> <script> document.forms[0].submit(); </script>访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
通常情况下,CSRF的防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。有三种方法被广泛用来防御CSRF攻击:验证token,验证HTTP请求的Referer,还有验证XMLHttpRequests里的自定义header。鉴于种种原因,这三种方法都不是那么完美,各有利弊。
根据HTTP协议,在HTTP头中有一个字段叫referer,它记录了该HTTP请求的来源地址。
在通常情况下,访问一个安全受限页面的请求来自于同一个网站,
比如需要访问http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。因此,要防御 CSRF 攻击,网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。
可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
这个Token的值必须是随机的。由于Token的存在,攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token时应注意Token的保密性,尽量把敏感操作由GET改为POST,以form或AJAX形式提交,避免Token泄露。
例子: 1、用户访问某个表单页面。 2、服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。 3、在页面表单附带上Token参数。 4、用户提交请求后, 服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。