爱客仕-前端团队博客园

温习csrf

什么是CSRF?
下面这个炸裂的图片就是

csrf

是不是感觉很奇幻,就点进了一篇文章。怎么就被攻击了呢
大家可以打开开发者工具,会发现有个图片请求 crsf?from=1&to=b,指向的服务器是localhost:8080
这就是一次crsf攻击,攻击的是服务器localhost,也就是我在本地开启的一个服务器
服务器上的日志清晰的打印出来了这次访问记录

1
[2016-10-17 20:22:30] [HTTP] GET /home/index/csrf?from=1&to=b 200 24ms

而且如果你之前访问过localhost:8080,那么这次访问还会把你在localhost:8080的cookie也带过去
这是一个很可怕的事情,因为这次请求完全在你不知情的请求下发生的
假设这个接口换成银行转账,或者知乎留言
在你刚刚访问完知乎之后,打开我这篇文章,你可能就被csrf了
你会在不知情的情况下被转账or被留言

在大部分正常的网站,这种操作不太可能是GET请求,上面仅仅为了举例

再看一个csrf的例子
假设一个网站嵌入了如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
<head>
<script type="text/javascript">
function steal(){
iframe = document.frames["steal"];
iframe.document.Submit("transfer");
}
</script>
</head>
<body onload="steal()">
<iframe name="steal" display="none">
<form method="POST" name="transfer"action="http://www.myBank.com/Transfer.php">
<input type="hidden" name="toBankId" value="11">
<input type="hidden" name="money" value="1000">
</form>
</iframe>
</body>
</html>

在你进入网站的同时
会自动提交iframe里面的表单,表单可能指向某银行的服务器
而你如果之前登陆过该银行,这次请求也许就会被服务器误认为是正常的请求而被执行
你账号的钱也许就这样被转了

怎么防范

上面举了两个例子来简要阐述csrf是怎么发生的,可以看到类似例子一的csrf制作起来真是超简单

当然,防御csrf的方式也五花八门:
简单描述几种常见的防御机制

___为了好描述,下文定义我们的网站为A,攻击者的网站为B

  1. 基本防护,不要将请求参数放到get请求的query中
    由上面例子可知,get请求的csrf是最容易的
  2. Token验证
    在每个HTTP请求里附加一部分信息是一个防御CSRF攻击的很好的方法,因为这样可以判断请求是否已经授权。这个“验证token”应该不能轻易的被未登录的用户猜测出来。如果请求里面没有这个验证token或者token不能匹配的话,服务器应该拒绝这个请求。

一个简单的token制造,加密session。
简单的方案,因为伪造攻击者不太可能获得服务器的session

1
2
3
4
5
6
7
8
9
10
11
// 伪代码
let session = ctx.sessionID()
let csrf_token = md5(session)
// 前端表单
<form method=”POST” action=”/transfer”>
<input type=”text” name=”toBankId”>
<input type=”text” name=”money”>
<input type=”hidden” name=”hash” value=”<%= $csrf_token %>”>
<input type=”submit” name=”submit” value=”Submit”>
</form>

表单由服务器模板直接生成在正常的网站 A 上
攻击者的 B 网站因为无法获取 A 网站的session,也就无法计算出表单的csrf_token这个字段
A网站服务端只需要校验csrf_token的正确性,便可以防御这类攻击了
当然这个防御并非完美,是建立在session不被盗取的基础上

生成token的方式还有很多很多,但或多或少都有些缺陷
显著的缺陷: 很多网站的表单是由js生成的

  1. 验证码
    目前我们访问大部分支付类网站时,都会要求输入手机验证码
    这个已经可以防御大部分csrf了,但不能每一个表单都要求用户输入手机验证码,
    会产生巨额的费用和降低用户体验

  2. Referer
    大多数情况下,当浏览器发起一个HTTP请求,其中的Referer标识了请求是从哪里发起的。如果HTTP头里包含有Referer的时候,我们可以区分请求是同域下还是跨站发起的,因为Referer离标明了发起请求的URL。网站也可以通过判断有问题的请求是否是同域下发起的来防御CSRF攻击。

    如果网站选择使用Referer来防御CSRF攻击的话,那么网站的开发人员就需要决定到底是使用比较宽松还是比较严格的Referer验证策略。如果采用宽松的Referer验证策略,网站就应该阻止Referer值不对的请求。如果请求里面没有Referer,就接收请求。尽管这个方法用的很普遍,但是它很容易被绕过。因为攻击者可以在header里面去掉Referer。例如,FTP和数据URL发起的请求里面就不包含Referer。如果使用严格的Referer验证策略,网站还要阻止没有Referer的请求。这样做主要是为了防止恶意网站主动隐藏Referer,但也会带来兼容性问题,比如会误杀一部分合法的请求,因为有些浏览器和网络的设置默认就是不含有Referer的。

总结

上面简单阐述了一下csrf跨站攻击的原理和防范措施
虽然大部分防范措施都是配合服务端开发人员编写(nodejs程序员则需要着重研究)
有兴趣的同学可以自行google和查阅相关书籍~~
本人水平有限,若有错误,还请指出