CSRF即Cross Site Request Forgery(跨站点请求伪造)。
用户在客户端(浏览器)上任何一个操作如提交表单、点击超链接、或者是页面资源的显示都是向服务器发起请求
而得以实现的,所以攻击者往往都是可以通过模拟真实用户的请求来“代替”用户完成操作的。
例如A用户删除id为18的文章的请求地址为:www.eco.com/delete?id=18
那么攻击者可以构造一个html页面,页面中有这样一段代码:
*** <img src="http://www.eco.com/delete?id=18" /> ***
(当然,用户会看到一张无法显示的图片)
然后引导A用户去访问攻击者的这个html页面,A用户看到了这样一张无法显示的图片,然后回到自己的博客,一看,
自己的id为18的文章不翼而飞了,这,就是跨站点请求伪造。当然了,CSRF肯定不会这么轻易就能成功的,因为大多
数web项目都会对http请求设置一个过滤器,用来验证发出请求的用户身份,使得CSRF的实施变得麻烦起来。
1.浏览器的cookie策略
我应该不止一次地说过,用户注册之后,会设置一个cookie(token)返回给客户端(浏览器),用于之后请求的身份
验证。
浏览器所持有的cookie分为两种,一种是“Session Cookie”、一种是“Third-party Cookie”也称为本地cookie,两者的
区别在于“Third-party Cookie”是服务器在Set-Cookie的时候指定了Expire时间(过期时间),到了过期时间,该cookie
失效;而“Session Cookie”没有指定过期时间,所以浏览器关闭之后就失效了。
Session Cookie保存在浏览器进程的内存空间中,Third-party Cookie保存在本地(下面分别是session-cookie和
Third-party Cookie)。
<?php header("Set-Cookie:cookie1=test1"); header("Set-Cookie:cookie2=test2;expire=Thu,01-Jan-2030 00:00:01 GMT;",false); ?>
假设A域a页面从服务端拿到了返回的如上两种Cookie,那么此时我们打开另一个A域的b页面,你会在b页面任意一个请求
的cookie看看到上述两种cookie,具体怎么看请求的cookie,下面附上博客园的一个请求案例:
正如你所看到的那样,这个请求自动携带了cookie。
接下来我们访问B域的a页面(浏览器不要关闭),而B域a页面中的一个图片标签又访问了A域;
*** <img src="http://www.a.com/delete?id=18" /> ***
你会发现,在该条请求的cookie里面你只能看到携带的A域的Session Cookie;
本地cookie是拿不到的,这是因为,有的浏览器出于安全考虑(IE),默认禁止在<img>、<iframe>、<script>等
标签中发送第三方Cookie(浏览器本地cookie)。而有的浏览器默认策略是允许发送第三方cookie。
下面是亲测案例:
用chrome登录某网站,控制台 document.cookie 拿到cookie;
然后用火狐同样登录该网站,但是没有登录,打开控制台,输入以上cookie(请忽略中间的拼写错误TT)
然后刷新火狐下的该网站,你会发现,当前状态变为登录,并且会员信息为cookie对应的会员信息。
2.P3P的介入
P3P头是W3C制定的一项关于隐私的标准,如果网站返回给浏览器的头中包含有P3P头,则在某种程度上说
将允许浏览器发送第三方cookie(本地cookie),在IE下即使是<iframe>、<script>等标签页不再拦截第三方cookie
的发送。
在网站的主要业务中,P3P头主要用于类似广告等需要跨域访问的页面,但很遗憾的是,设置了P3P之后,对于Cookie
的影响将扩大到整个域中的所有页面。
(以下内容是我思索再三根据自己的理解总结的,刚开始看的时候想不明白)
我们通常都是在A域下页面访问A域服务器的Set-cookie接口,但是换一种方式去B域下页面访问A域的Set-cookie接口呢?
请看图:
由此看来,通过src属性set-cookie是有跨域限制的(IE),这和浏览器限制javascript权限,对script跨域请求的资源不
能实现读写应该是一个道理。
对于以上的情况,加入了P3P头之后,情况就不同了,P3P允许跨域访问隐私数据,从而可以实现跨域Set-Cookie
以及发送第三方cookie。
以下是P3P头:
<?php header("P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR""); header("Set-Cookie:cookie1=test1"); header("Set-Cookie:cookie2=test2;expire=Thu,01-Jan-2030 00:00:01 GMT;",false); ?>
3.CSRF的防御
3.1验证码
验证码强制用户与应用进行交互,才能完成最终请求,但是网站不可能对所有操作都加上验证码,因此验证码只能作
为防御CSRF的一种手段,而不能作为主要的解决方案。
3.2Referer Check
正常页面http请求的referer头必然是当前页面所在的域,如果不是的话极有可能是CSRF攻击,我们可以通过Referer
Check来判断用户是否被CSRF攻击。但是,服务器并不是什么时候都能获取到referer:
用时候用户出于安全的考虑,限制referer的发送;
某些情况下,出于安全考虑,浏览器也不会发送referer,比如HTTPS转HTTP;
在Flash的一些版本中,曾经可以发送自定义referer,新版本不在允许发送自定义referer头。
所以,还是无法依赖Referer Check作为CSRF攻击的主要手段,但是可以用来监控CSRF攻击的发生。
3.3Token
CSRF攻击之所以能够成功,是因为攻击者能够猜测操作所需要的所有参数,于是对于所有的请求新增一个参数Token
这个Token要足够随机,必须使用足够安全的随机数生成算法,Token应该作为一个秘密,为用户和服务器共同持有,
不能让第三方知晓。实际应用中Token存于Session或者本地Cookie。
Token需要同时存放在提交的表单(hidden)和Session中,服务器验证用户提交的表单Token和Session中的Token是否
一致,如果一致则请求合法,否则不合法,可能是CSRF攻击。
Token使用的注意事项:
如果用户提交了表单,则Token应该视为已消耗,应当再次生成一个新的Token到session中;
Token如果放在url中,当前页面若嵌入了一个攻击者服务器的请求,则包含Token的url可能会被当做referer发送到攻击者
的服务器,所以应当尽量把Token放在表单中,把GET改为POST;
另外,如果攻击者通过XSS获取到了Token那么CSRF的Token防御也就变得毫无意义了,所以安全防御体系是相辅相成,
缺一不可的。
4.ClickJacking
(由于点击劫持不难理解,而且感觉需要总结的不多,故不另开,就在此篇结尾一带而过吧)
点击劫持是一种视觉上的欺骗,攻击者用一个透明的iframe覆盖在网页上,然后诱使用户进行操作,此时,用户在不知情
的情况下点击了透明的iframe。可以通过调整iframe的位置迫使用户正好点击在iframe页面的一些特定功能上。
下面用隐藏的div来模拟iframe做个示范:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div style="200px;height:200px;border:1px solid;">用户可以看到的</div> <div style="position:absolute;top:10px;opacity:0;background:pink;200px;height:100px;" onclick="javascript:alert('hello');"></div> </body> </html>
用户看到的界面是这样的:
当用户点击没有绑定事件的第一个div后,触发了隐藏在相同位置上的div的单击事件:
攻击者可以利用点击劫持来让用户做一些始料未及的事情。
与此类似的还有XSIO(图片覆盖攻击)、拖拽劫持、触屏劫持。
5.ClickJacking防御
针对传统的ClickJacking可以通过禁止跨域的Iframe来防范,这种方法叫做 frame busting;
if(top.location !=location){ top.location = self.location; }
更多相关知识请自行百度。