CSRF跨站请求伪造:攻击者盗用了合法用户的身份,以合法用户的名义发送恶意请求,对服务器来讲这个请求是彻底合法的,可是却完成了攻击者所指望的操做,好比以合法用户的名义发送邮件、发消息,添加系统管理员,甚至于购买商品、虚拟货币转帐等。 程序员
详细过程:浏览器
其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User 1为Web A网站的合法用户。安全
CSRF其实是利用站点对用户的信任。服务器
CSRF攻击能够在受害者绝不知情的状况下以受害者名义伪造请求发送给受攻击站点,从而在并未受权的状况下执行在权限保护之下的操做。session
好比说,受害者Bob在银行有一笔存款,经过对银行的网站发送请求http://bank.example/withdraw?account=alen&amount=100&for=alen2
可使alen把100的存款转到alen2的帐号下。一般状况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的Session,而且该Session的用户Alen已经成功登录。黑客Hack本身在该银行也有帐户,他知道上文中的URL能够把钱进行转账操做。Hack能够本身发送一个请求给银行:http://bank.example/withdraw?account=alen&amount=100&for=Hack
。可是这个请求来自Hack而非Alen,他不能经过安全认证,所以该请求不会起做用。并发
这时,Hack想到使用CSRF的攻击方式,他先本身作一个网站,在网站中放入以下代码: src="http://bank.example/withdraw?account=alen&amount=100&for=Hack"
,而且经过广告等诱使Alen来访问他的网站。当Alen访问该网站时,上述URL就会从Alen的浏览器发向银行,而这个请求会附带Alen浏览器中的Cookie一块儿发向银行服务器。大多数状况下,该请求会失败,由于他要求Alen的认证信息。可是,若是Alen当时恰巧访问他的银行后不久,他的浏览器与银行网站之间的Session还没有过时,浏览器的Cookie之中含有的认证信息。这时,悲剧发生了,这个URL请求就会获得响应,钱将从Alen的帐号转移到Hack的帐号,而Alen当时绝不知情。等之后Alen发现帐户钱少了,即便他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而Hack则能够拿到钱后逍遥法外。异步
根据HTTP协议,在HTTP头中有一个Referer字段,它记录了该HTTP请求的来源地址。在一般状况下,访问一个安全受限页面的请求来自于同一个网站,好比须要访问http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory
,用户必须先登录bank.example,而后经过点击页面上的按钮来触发转帐事件。这时,该转账请求的Referer值就会是转帐按钮所在的页面的URL,一般是以 bank.example域名开头的地址。而若是黑客要对银行网站实施CSRF攻击,他只能在他本身的网站构造请求,当用户经过黑客的网站发送请求到银行时,该请求的Referer是指向黑客本身的网站。所以,要防护 CSRF攻击,银行网站只须要对于每个转帐请求验证其Referer值,若是是以bank.example开头的域名,则说明该请求是来自银行网站本身的请求,是合法的。若是Referer是其余网站的话,则有多是黑客的CSRF攻击,拒绝该请求。网站
这种方法的显而易见的好处就是简单易行,网站的普通开发人员不须要操心CSRF的漏洞,只须要在最后给全部安全敏感的请求统一增长一个拦截器来检查Referer的值就能够。特别是对于当前现有的系统,不须要改变当前系统的任何已有代码和逻辑,没有风险,很是便捷。编码
然而,这种方法并不是万无一失。Referer的值是由浏览器提供的,虽然HTTP协议上有明确的要求,可是每一个浏览器对于Referer的具体实现可能有差异,并不能保证浏览器自身没有安全漏洞。使用验证Referer值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来说,这样并不安全。事实上,对于某些浏览器,好比IE6,目前已经有一些方法能够篡改Referer值。若是bank.example网站支持IE6浏览器,黑客彻底能够把用户浏览器的Referer值设为以bank.example域名开头的地址,这样就能够经过验证,从而进行CSRF攻击。url
即使是使用最新的浏览器,黑客没法篡改Referer值,这种方法仍然有问题。由于Referer值会记录下用户的访问来源,有些用户认为这样会侵犯到他们本身的隐私权,特别是有些组织担忧Referer值会把组织内网中的某些信息泄露到外网中。所以,用户本身能够设置浏览器使其在发送请求时再也不提供Referer。当他们正常访问银行网站时,网站会由于请求没有Referer值而认为是CSRF攻击,拒绝合法用户的访问。
CSRF攻击之因此可以成功,是由于黑客能够彻底伪造用户的请求,该请求中全部的用户验证信息都是存在于Cookie中,所以黑客能够在不知道这些验证信息的状况下直接利用用户本身的Cookie来经过安全验证。要抵御CSRF,关键在于在请求中放入黑客所不能伪造的信息,而且该信息不存在于Cookie之中。能够在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端创建一个拦截器来验证这个token,若是请求中没有token或者token内容不正确,则认为可能 CSRF攻击而拒绝该请求。
这种方法要比检查Referer要安全一些,token能够在用户登录后产生并放于session之中,而后在每次请求时把token从session中拿出,与请求中的token进行比对,但这种方法的难点在于如何把token以参数的形式加入请求。对于GET请求,token将附在请求地址以后,这样URL就变成http://url?csrftoken=tokenvalue
。而对于POST请求来讲,要在form的最后加上<input type=”hidden” name=”csrftoken” value=”tokenvalue”/>
,这样就把token以参数的形式加入请求了。可是,在一个网站中,能够接受请求的地方很是多,要对于每个请求都加上token是很麻烦的,而且很容易漏掉,一般使用的方法就是在每次页面加载时,使用JavaScript遍历整个Dom树,对于Dom中全部的a和 form标签后加入token。这样能够解决大部分的请求,可是对于在页面加载以后动态生成的HTML代码,这种方法就没有做用,还须要程序员在编码时手动添加token。
该方法还有一个缺点是难以保证token自己的安全。特别是在一些论坛之类支持用户本身发表内容的网站,黑客能够在上面发布本身我的网站的地址。因为系统也会在这个地址后面加上token,黑客能够在本身的网站上获得这个token,并立刻就能够发动CSRF攻击。为了不这一点,系统能够在添加token的时候增长一个判断,若是这个连接是链到本身本站的,就在后面添加token,若是是通向外网则不加。不过,即便这个csrftoken不以参数的形式附加在请求之中,黑客的网站也一样能够经过Referer来获得这个token值以发动CSRF攻击。这也是一些用户喜欢手动关闭浏览器Referer功能的缘由.
这种方法也是使用token并进行验证,和上一种方法不一样的是,这里并非把token以参数的形式置于HTTP请求之中,而是把它放到 HTTP 头中自定义的属性里。经过XML HTTP Request这个类,能够一次性给全部该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了上种方法在请求中加入token的不便,同时,经过XML HTTP Request请求的地址不会被记录到浏览器的地址栏,也不用担忧token会透过Referer泄露到其余网站中去。
然而这种方法的局限性很是大。XML Http Request请求一般用于Ajax方法中对于页面局部的异步刷新,并不是全部的请求都适合用这个类来发起,并且经过该类请求获得的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操做,给用户带来不便。另外,对于没有进行CSRF防御的遗留系统来讲,要采用这种方法来进行防御,要把全部请求都改XML Http Request请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。