CSRF跨站请求伪造的安全防护

本文主要介绍和总结了CSRF跨站请求伪造的基本原理和主要防范措施,工作中有用到的朋友不妨收藏转发一下,以备您参考 。
什么是CSRF?CSRF跨站点请求伪造(Cross—Site Request Forgery),跟类似XSS攻击一样,存在着巨大的安全隐患,你可以这样来理解:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却偷偷完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、转账等 。
CSRF攻击原理及过程假如:Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户 。攻击大概过程如下:

  1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A 。
  2. 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A 。
  3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B 。
  4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A 。
  5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求 。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行 。
如何防御CSRF攻击?目前,我们工作中常用于防御CSRF攻击主要有三种策略:
一、验证 HTTP Referer字段
根据 HTTP 协议,在 HTTP 头 中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址 。通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问
http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件 。这时,该转账请求的Referer值就会是转账按钮所在的页面的 URL,通常是以bank.example 域名开头的地址 。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站 。因此,要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的 。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求 。
这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心 CSRF 的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以 。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷 。
然而,这种方法并非万无一失 。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞 。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全 。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer 值 。如果 bank.example 网站支持IE6浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 bank.example 域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击 。
即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题 。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer的值 会把组织内网中的某些信息泄露到外网中 。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer 。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问 。
二、在请求地址中添加token并验证
CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证 。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中 。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求 。


推荐阅读