CSRF是什么?

CSRF(Cross Site Request Forgery),中文是跨站点请求伪造。CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

举个例子

简单版:

假如博客园有个加关注的GET接口,blogUserGuid参数很明显是关注人Id,如下:

http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx?blogUserGuid=4e8c33d0-77fe-df11-ac81-842b2b196315

那我只需要在我的一篇博文内容里面写一个img标签:

<img style="width:0;" src="http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx?blogUserGuid=4e8c33d0-77fe-df11-ac81-842b2b196315"   />

利用width=0隐藏点击链接之后的效果,点击此链接后页面不会有任何变化,但关注人已经被添加。

升级版:

假如博客园还是有个加关注的接口,不过已经限制了只获取POST请求的数据。这个时候就做一个第三方的页面,但里面包含form提交代码,然后通过QQ、邮箱等社交工具传播,诱惑用户去打开,那打开过博客园的用户就中招了。

在说例子之前要纠正一个iframe问题,有人会直接在第三方页面这样写。如下:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
<title>CSRF SHOW</title>
</head>
     <body>
          <!--不嵌iframe会跳转-->
          <iframe style="display:none;">
               <form  name="form1" action="http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx" method="post">
                    <input type="hidden" name="blogUserGuid" value="4e8c33d0-77fe-df11-ac81-842b2b196315"/>
                    <input type="submit" value>
               </form>
               <script>
                    document.forms.form1.submit();
               </script>
          </iframe>
     </body>
</html>

首先说,这样写是不会起任何作用的,因为这里涉及了一个同源策略的问题。iframe定义的这个链接和我即将访问的链接受同源策略的限制,他们的访问端口不同,因此无法取得想到达到的效果。因此我们需要再嵌入一层iframe

<!DOCTYPE HTML>
<html lang="en-US">
<head>
<title>CSRF SHOW</title>
</head>
     <body>
          <iframe style="display:none;" src="test2.html"></iframe>
     </body>
</html>
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<title>CSRF GET</title>
<body>
     <form  name="form1" action="http://www.cnblogs.com/mvc/Follow/FollowBlogger.aspx" method="post">
          <input type="hidden" name="blogUserGuid" value="4e8c33d0-77fe-df11-ac81-842b2b196315"/>
          <input type="submit" value>
     </form>
     <script>
          document.forms.form1.submit();
     </script>
</body>
</html>

可以看到第一个列表中既没写出访问端口,也没写出域名,因此是不定向的,可以连接两个不同源也页面做到互通。

CSRF攻击的本质原因

CSRF攻击是源于Web的隐式身份验证机制!Web的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。CSRF攻击的一般是由服务端解决。

 

CSRF工具的防御手段

 

1. 尽量使用POST,限制GET

 

GET接口太容易被拿来做CSRF攻击,看第一个示例就知道,只要构造一个img标签,而img标签又是不能过滤的数据。接口最好限制为POST使用,GET则无效,降低攻击风险。

 

当然POST并不是万无一失,攻击者只要构造一个form就可以,但需要在第三方页面做,这样就增加暴露的可能性。

 

2. 浏览器Cookie策略

 

IE6、7、8、Safari会默认拦截第三方本地Cookie(Third-party Cookie)的发送。但是Firefox2、3、Opera、Chrome、Android等不会拦截,所以通过浏览器Cookie策略来防御CSRF攻击不靠谱,只能说是降低了风险。

 

PS:Cookie分为两种,Session Cookie(在浏览器关闭后,就会失效,保存到内存里),Third-party Cookie(即只有到了Exprie时间后才会失效的Cookie,这种Cookie会保存到本地)。

 

PS:另外如果网站返回HTTP头包含P3P Header,那么将允许浏览器发送第三方Cookie。

 

3. 加验证码

 

验证码,强制用户必须与应用进行交互,才能完成最终请求。在通常情况下,验证码能很好遏制CSRF攻击。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段,不能作为主要解决方案。

 

4. Referer Check

 

Referer Check在Web最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”(Referer值是否是指定页面,或者网站的域),如果都不是,那么就极可能是CSRF攻击。

 

但是因为服务器并不是什么时候都能取到Referer,所以也无法作为CSRF防御的主要手段。但是用Referer Check来监控CSRF攻击的发生,倒是一种可行的方法。

 

5. Anti CSRF Token

 

现在业界对CSRF的防御,一致的做法是使用一个Token(Anti CSRF Token)。

 

例子:

 

1. 用户访问某个表单页面。

 

2. 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。

 

3. 在页面表单附带上Token参数。

 

4. 用户提交请求后, 服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。

 

这个Token的值必须是随机的,不可预测的。由于Token的存在,攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token时应注意Token的保密性,尽量把敏感操作由GET改为POST,以form或AJAX形式提交,避免Token泄露,网上关于anticsrftoken的模板代码也很多。而且大多数防csrf的手段也都是加入token验证机制。

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄