0x01 Brief Description
csrf 跨站伪造请求,请求伪造的一种,是由客户端即用户浏览器发起的一种伪造攻击。攻击的本质是请求可以被预测的到。
在了解csrf攻击之前,需要了解浏览器的cookie策略,浏览器所持有的Cookie分为两种,一种是存放在浏览器进程内存中的session cookie,另外一种是保存在本地的Thirdy party cookie,如果浏览器从一个域的页面中,要加载另一个域的资源,由于安全原因,某些浏览器会阻止Tirdy party Cookie的发送,比如IE、safari,有些是允许的比如 Friefox、chrome,之所以csrf能攻击成功,是由于使用了允许发送第三方cookie的浏览器,导致了csrf攻击的成功。此外值得注意的是jsonp的劫持本质上也是csrf。
0x02 Vulnerability impact
csrf攻击能够劫持用户在已登录的web站点上执行非本意的操作。
攻击者盗用你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
个人认为产生CSRF漏洞的原因主要有两点:1.一方面是开发者不够审慎,编写的web应用程序存在漏洞被恶意利用,另一方面,因为web浏览器对cookie和http身份验证等会话信息的处理存在一定的缺陷(隐式的认证方式)。
csrf 进击的巨人,csrf在近年来csrf能做的事情越来越多,对应的攻击也越来越多,比如,一些内网资源由于防火墙做了限制只能是内网的资源去访问,所以这个时候可以使用客户端请求伪造即csrf,或者使用ssrf进行内网探测和内网攻击,有点儿“借刀杀人”的感觉
0x03关于Referer伪造
在csrf的防御中有这样一个措施是添加对Referer字段的验证(一般是白名单过滤),但是之前网上有看到说可以伪造Referer,遂就研究一下怎么绕过Referer。
首先来学习一下,在发送ajax请求的时候,我们可以发送自己定制的Header字段,那么我们是否就可以添加Referer字段,从而覆盖掉浏览器自己所“识别”的Referer字段呢,简单的测试代码如下:
1.php
<?php
?>
<a href="http://www.51m0rk.xyz:81/referertest/2.php"> Click </a>
2.php
<?php
//echo "Referer: ";
//echo getenv('HTTP_REFERER');
echo "</br>";
foreach (getallheaders() as $name => $value) {
echo "$name: $value</br>";
}
?>
ajax.html
<html>
<head>
<script type="text/javascript">
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest(); }
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
var url = "http://www.51m0rk.xyz:81/referertest/2.php"
xmlhttp.open("GET",url,true);
xmlhttp.setRequestHeader("my-head", "M0rk")
xmlhttp.send();
}
</script>
</head>
<body> <h2>AJAX</h2>
<button type="button" onclick="loadXMLDoc()">请求数据</button>
<div id="myDiv"></div> </body>
</html>
然后我们测试:
当点击之后会显示来源Referer字段,如下图:
那么我们现在就尝试用ajax请求的方式试图修改Referer字段。访问ajax.html
诶?有我们的自定义头,那试试修改成Referer试试呢,看会不会覆盖
比如修改成这样:
刷新页面如下图所示:
可以看到并没有出现我们想要的结果,打开chrome的调试器,我们发现有一处报错。
可见,浏览器已拒绝了我们发送了我们自定义的Referer,即ajax的请求的头中Referer字段是我们不能自定义的,除此之外,笔者还测试了像Host、User-agent也是不能自定义的。
其它浏览器的情况呢?
经测试firefox也不会让你发送自定义的Referer,但是User-Agent 却可以修改,此外,firefox并不会像chrome那样有报错。
但是就真的没有可以自定义Referer的吗,有,之前看到过一篇文章讲IE 通过activeX控件可以修改到Referer Link,但是像csrf这种“欺骗”攻击,ie况且安装和开启了activeX的毕竟还是少数,再有就是安全研究,修改Referer的方法就很多了,比如burpsuite或者firefox的ModifyHeaders插件等,当然后端语言可以轻松的去伪造Referer。
总结就一句话:Referer如果可以伪造,那就是浏览器的漏洞,你可以在服务器上伪造,但是不能在浏览器上伪造Referer。
可见验证Referer还是一种相对安全的一种方法,但是也不一定,有时候为了需要,某些操作虽然验证了Referer,但是Referer允许为空,因为用户有可能并不是通过跳转过来的。那么允许空Referer的情况下就有一些绕过的姿势了。比如
- 不同协议之间的跳转,比如我从qq消息中 http://www.51m0rk.xyz:81/referertest/2.php 页面显示的Referer就为空,此外还有比如https/ftp/file/javascript等
- 猜测后端代码可能是某关键字或者某个正则,则利用这个缺陷去构造,比如代码中检测了referer中有qq.com,然后你去申请一个qq.com.fuck.cn,就有可能绕过
。。。
0x04 Defense
1.添加对Referer的验证,且确保验证的方式方法足够安全。
2.添加token字段(确保token足够随机,不被攻击者猜测的到)。
3.重要操作增加验证码(可能会降低用户体验,此外增加验证码还可以在一定程度上防御cc攻击)。
0x05 Reference
1.http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
2.《xss跨站脚本攻击剖析与防御》邱永华著
3.https://www.youtube.com/watch?v=hW2ONyxAySY
4.http://0x007.blog.51cto.com/6330498/1610946
5.http://blog.163.com/yl32940@126/blog/static/50356084201453093323474/