CSRF 跨站请求伪造

CSRF 跨站请求伪造_第1张图片
CSRF

CSRF全称Cross-Site Request Forgery跨站请求伪造,也被称为One Click AttackSession Riding,通常缩写为CSRFXSRF

CSRF 跨站请求伪造_第2张图片
CSRF

攻击原因

CSRF攻击是冒充信任用户向服务器发送非预期请求的一种攻击方式

例如:CSRF攻击者在用户已经登录目标站点后,诱使用户访问一个攻击页面,利用目标站点对用户的信任,以用户身份对目标站点发起伪造用户操作的请求,以达到攻击目的。

CSRF 跨站请求伪造_第3张图片
CSRF

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

检测CSRF漏洞最简单的方式就是抓取一个正常的请求数据包,去掉Refer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。

防御手段

  • 尽量使用POST 限制使用GET
    GET接口太容易被拿来做CSRF攻击,使用POST方式以降低攻击风险。
  • 添加验证码
    验证码强制用户必须与应用进行交互,才能完成最终请求。通常情况下,验证码能够很好的遏制CSRF攻击。但处于用户体验考虑,验证码做出辅助手段会比较不错。
  • Anti CSRF Token
  • RESTful API
  • Referer Check

浏览器Cookie策略

浏览器的Cookie可以分为:

  • Session Cookie 会话Cookie,保存在内存中,浏览器关闭后立即失效。
  • Third-party Cookie 第三方Cookie,保存在本地,只有到了失效时间才会失效的Cookie

若HTTP请求返回的响应头中包含了P3P Header字段,则允许浏览器发送第三方Cookie

浏览器默认的Cookie策略:

  • IE6IE7IE8Safari默认会拦截第三方本地Cookie的发送
  • FireFox2FireFox3OperaChromeAndroid等默认不会拦截

通过浏览器Cookie策略来防御CSRF攻击并不靠谱,只能说是降低了风险。

CSRF 跨站请求伪造_第4张图片
CSRF

Referer Check

Referer Check也就是验证HTTP请求中的Referer字段

Referer Check在Web中最常见的应用是“防盗链”,例如防止图片盗链。同理,也可以用来检查请求是否来自合法的“源”Referer,即判断是否是来自指定页面或域。如果不是则极有可能是CSRF攻击。但因服务器并不是什么时候都能获取到Referer,所以无法作为CSRF防御的主要手段。通过Referer Check来监控CSRF攻击的发生,倒是一种可行的方案。

根据HTTP协议,在HTTP头中有一个Referer字段记录了该HTTP请求的来源地址,正常情况下访问一个安全受限的页面请求都是来自于同一个站点的。因此要防御CSRF攻击,只需要对每个请求验证其Referer值。虽然这个方法简单易行,但并非万无一失。

由于Referer值是由浏览器提供的,虽然HTTP协议上有明确要求,但每个浏览器对Referer的具体实现存在差别,并不能保证浏览器自身没有安全漏洞。

使用验证Referer值得方式,就是把安全性都依赖于第三方浏览器来保证。从理论上来讲,这样并不安全。

用户可以设置浏览器使其在发送请求时不再提供Referer,当他们正常访问站点时,站点会因为请求没有Referer值而认为是CSRF攻击,拒绝合法用户的访问。

Anti CSRF Token

现在对CSRF攻击的防御一致的做法是使用一个Token

比如:当用户访问某个表单时,服务器会提前生成一个随机的Token,存放到用户会话Session中或浏览器Cookie中,并在表单中附带这个Token参数。当用户提交请求后,服务器验证表单中的Token是否与用户SessionCookie中的Token一致,若一致则为合法请求否则为非法请求。需要注意的是Token的保密性和随机性。

CSRFToken仅仅用于对抗CSRF攻击,如果同时又存在XSS漏洞时,这个方案也时空谈。

在请求地址中添加token并验证(Secure Token)

CSRF攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此黑客可能在不知道这些验证信息的情况下直接利用自己的Cookie来通过安全验证。要抵御CSRF关键自于在请求中放入黑客所不能伪造的信息,并且该信息不存在Cookie之中。

可以在HTTP请求中以参数的形式加入一个随机产生的Token,并在服务器端建立一个拦截器来验证这个Token,如果请求中没有Token或Token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

这种方法比要检查Refer安全一些,Token可以在用户登录后产生并放在Session之中,然后每次请求时把Token从Session中拿出于请求中的Token进行比对。对于GET请求,可以直接将Token以参数形式附加到请求地址之后。对于POST请求,可以在表单中添加一个隐藏域。注意,需要为Token设置失效时间。

但这个方法的难点在于:如何把Token以参数的形式加入请求。为什么了,因为一个站带中可以接受请求的地方非常多,对于每个请求都添加Token是很麻烦的,并且容易漏掉。

通常使用的方法是每次页面加载时,使用JavaScript遍历整个DOM树,对于DOM中所有的锚点

标签后加入Token,这样可以解决大部分的请求,但是对于在页面加载之后动态生成生成HTML代码时这个方法就没有作用,还是需要开发人员编码时手工添加Token。

这种方法有一个缺点是难以保证Token本身的安全,当黑客在站点中发表自己的站点链接地址时,由于系统会为地址添加Token,黑客可在自己的站点上得到这个Token,并马上发送CSRF攻击。为了避免这一点,系统可以在添加Token的时候增加一个判断,如果这个链接是站内的就添加Token,如果是外链则不添加。不过即使Token不以参数的形式附加到请求之中,黑客的站点也同样可以通过Refer来得到这个Token值发送CSRF攻击,这也是一些用户喜欢手动关闭浏览器Refer的原因。

在HTTP头中自定义属性并验证

这种方式也是使用Token进行验证,和“在请求地址中添加token并验证”的方法不同的是,这里并不是将Token以参数的形式放到HTTP请求之中,而是把Token放到HTTP头的自定义属性中。通过XMLHttpRequest类可以一次性给所有该类请求添加Token。同时,通过XMLHttpRequeset请求的地址不会被记录到浏览器的地址栏,也不用担心Token会透过Refer泄漏到其它网站中区。

然后这种方法的局限性很大,XMLHttpRequest请求只能用于AJAX方法中,并非所有请求都适合使用AJAX发起请求,而且通过XMLHttpRequest请求得到的页面不能被浏览器记录,从而进行前进、后退、刷新、收藏等操作时,给用户带来不便。

另外,对于没有进行CSRF防护的系统采用这种方法来进行防护,要把所有请求都改造成XMLHttpRequest请求,这样几乎重写整个系统,代价无疑是不能接受的。

未完待续...

你可能感兴趣的:(CSRF 跨站请求伪造)