跨站点请求伪造(CSRF)

◇◆丶佛笑我妖孽 提交于 2020-03-03 03:47:45

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="width:200px;height:200px;border:1px solid;">用户可以看到的</div>
    <div style="position:absolute;top:10px;opacity:0;background:pink;width: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;
}

更多相关知识请自行百度。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!