前言:不想读完的,可以理解这一句话,“如果你能理解XSS攻击的话,那么你一定认同XSS攻击是利用盗取的高权限cookie来进行的,相较而言CSRF并不干偷盗之事,而是借刀杀人”,这是我自己的感想,不认同的也不强求
CSRF(cross-site request forgery),跨站请求伪造,算了算了,概念性的我就不多说了,都能百度到,下面我直接说重点吧。
CSRF的攻击原理是什么,简单说就是利用了高权限帐号(如管理员)的登录状态或者授权状态去做一些后台操作,但实际这些状态并没有被我们直接获取到(获取那是XSS干的事)。
GET方式演示CSRF攻击
我们这里假设有个网站test.com,包含一个登录页面(login.php)和一个付款页面(pay.php)
login.php:
<?php
setcookie('uid', 1, time()+86400);
echo "your uid is {$_COOKIE['uid']}";
pay.php:
<?php
//身份验证
if (!isset($_COOKIE['uid']) || $_COOKIE['uid']< 0) {
die('login error!');
}
//金额获取
if (!isset($_GET['money'])) {
die('no money');
}
//收款人获取
if (!isset($_GET['to_who'])) {
die('nobody');
}
$uid = $_COOKIE['uid'];
$money = $_GET['money'];
$to_who = $_GET['to_who'];
//。。。。。。
//此处应该还有相关DB操作,略去
echo "transfer {$money} yuan to {$to_who}!";
打开login.php,模拟登录,可以看到登录成功:
your uid is 1
登录完成后我们打开pay.php进行转账,转1000元给father,GET请求构造:http://test.com/pay.php?money=1000&to_who=father
访问得到转账成功的响应:
transfer 1000 yuan to father!
以上是用户正常操作,这时黑客发现了该网站的CSRF漏洞,于是立刻伪造了一个页面,页面上预置了一个UC震惊部的超链接,超链接指向http://test.com/pay.php?money=1000&to_who=hacker
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<a href="http://test.com/pay.php?money=1000&to_who=hacker" taget="_blank">震惊!男人看了会沉默,女人看了会流泪!不转不是中国人!<a/>
</body>
</html>
如上,收款人被篡改成了黑客,如果我们是中国人,就一定会毫不犹豫的点击链接,因为不转不是中国人!!然后,然后。。。我们就把自己账户的1000元开心的转给了黑客。
为什么会出现这种情况,我们在别的网站点击链接居然能扣自己账户的钱?
点击链接前,我们已经登录了信任网站test.com,而这个这个链接是我们自己发送的,test.com会识别当前已经登录,然后转账,网站无法判断到底是谁让我们点击的。
从上面这个实例可知,完成CSRF攻击流程:
1、用户登录了信任的网站A,并且保存登录状态
2、黑客找出网站A没有防御的链接,通过社会工程学伪装,诱导点击。
3、只要登录状态保持,用户主动访问目标链接,则攻击成功。
有人说那每次访问其他网站,把之前的网站都注销。是的,这个办法可以,但这么做这现实吗?我们需要注销许多常用的网站,下次登录又要输入用户名和密码,极其反人类。这肯定不是最佳办法,防御措施应该让程序员考虑,用户别乱点链接是最重要的。
以上演示了GET方式攻击,有人说那我把method改为POST吧,其实稍微动动脑也知道不行,POST请求我们同样可以伪造,隐藏表单的方式我们见多不怪了,所以仅仅依靠简单的POST传输依旧无济于事。
如此一来,不管哪种访问方式都可能受到攻击。所以,这并不是GET和POST谁更安全的问题,POST只是提高了攻击门槛和成本。
划重点,那么CSRF能够攻击的根本原因是:服务器无法识别你的来源是否可靠。
最后,我们聊一聊前辈是如何防御CSRF攻击的:
防御的方法有很多:
1、比如加上验证码。但这么做很繁琐,并且影响用户体验。
2、比如转账需要二次密码验证,现在很多银行就这么搞的。
3、确认来源是否可靠(推荐)
1和2都是同一个思路,那就是验证请求合法性,从这一思路出发,前辈想出了下面几种方法:
验证HTTP Referer 字段
HTTP协议里面定义了一个访问来源的字段,这个字段叫Referer。黑客伪造的链接或表单是在其他网站上,所以我们可以判断Referer是否为自身网站,如果是,则允许访问,如果不是,则拒绝访问。
但是这种方法是有缺陷的,上面实验尝试过,如果对方在QQ上发送给你一个链接呢?点击的时候属于主动点击,此时一样没有Referer。程序会把它归属为安全请求,那么就被绕过了。并且如果某些低版本的浏览器存在漏洞(比如IE6),Referer很有可能被篡改,所以这个方法并非十全十美。
服务端验证请求的token一致性
CSRF攻击的核心原理就是利用用户验证信息储存cookie中,发送请求,使得服务器无法判断真伪,而token之所以能够拦截,就是因为它是CSRF攻击过程中几乎不可能伪造的东西。
实现原理:在服务端生成一个随机的token,加入到HTTP请求参数中,服务器拦截请求,查看发送的token和服务端的是否一致,若一致,则允许请求;若不一致,则拒绝请求。
注意:一定要生成唯一的或者随机性较大的token。如果token可以被爆破,一样可以伪造请求,进行攻击。
参考文章:https://blog.csdn.net/li741350149/article/details/62887524
Ajax防御CSRF
实际上Ajax防御的思想也可以利用上面的token验证方式。
IBM上一篇文章说Ajax防御时,在 HTTP 头中自定义属性并验证token。
它是这么说的:
把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
总结
CSRF防御原则:
- GET方式不能用于更新资源的操作
- POST方式请求加上随机token验证
网友评论