CSRF跨站域请求伪造攻击
CSRF简介
- CSRF(Cross Site Request Forgery,跨站域请求伪造),也被称为 “One Click Attack” 或者 Session Riding,通常缩写为 CSRF 或者 XSRF 。
- 尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS 利用站点内的信任用户,而 CSRF 则通过伪装成来自受信任用户的请求来利用受信任的网站。
CSRF原理
- 首先是存在CSRF漏洞的网站A,以及存在恶意攻击代码的网站B,还有受网站A信任的用户C
- 用户C通过浏览器正常访问网站A,
- 通过验证在浏览器生成cookie信息
- 用户C在没有登出网站A的情况下,访问网站B
- 网站B返回给用户一些攻击性代码,并请求访问网站A
- 这样网站B就在用户不知情的情况下,利用浏览器保存的cookie信息对网站A进行访问请求,导致网站B的恶意代码能够在网站A被信任执行
- 需要满足两个条件:
- 登录受信任网站A,并生成cookie
- 不登出网站A的情况下,访问网站B
CSRF危害
- 你不能保证你登录了一个网站后,不再打开一个 tab 页面并访问另外的网站。
- 你不能保证你关闭浏览器了后,你本地的 Cookie 立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了…)
- 上面所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
- 攻击者盗用用户身份进行恶意行为,包括以他人名义发送邮件,盗取账户,购买商品等等
- 更重要的是个人隐私的泄露以及财产安全
CSRF攻击类型
GET型
- 通过GET请求进行修改
- 比如用户修改邮箱是通过GET请求修改的,例如
/user.php?id=1&email=123@163.com
- 意思是用户id为1的用户需要修改邮箱为
123@163.com
- 那么恶意网站当中有一段代码内容,例如
<img src=/user.php?id=1&email=abc@163.com>
- 那么,只需要用户在打开修改邮箱的同时打开了这个恶意网站,那么浏览器就会带上用户的cookie信息向修改邮箱的网站发出GET请求,导致该用户的邮箱被修改成了
abc@163.com
POST型
- POST型相较于GET型来说,危害没那么大,通常是使用一个自动提交表单
- 例如在购买商品时,网站会处理购买时用户余额的扣除,会在一个地址内进行,如
/coures/user/handler/25332/buy.php
- 通过提交表单在buy.php当中处理扣除信息
1
2
3
4<form action=/coures/user/handler/25332/buy method=POST>
<input type="text" name="xx" value="xx" />
</form>
<script> document.forms[0].submit(); </script> - 访问该页面,表单会自动提交,相当于模拟用户提交一次POST
CSRF防御
验证HTTP Referer字段
- 根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址 。
- 在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问
http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory
,用户必须先登陆bank.example
,然后通过点击页面上的按钮来触发转账事件。 - 因此,要防御 CSRF 攻击,网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。
优点
- 这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心 CSRF 的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。
缺点
- 然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以 篡改 Referer 值 。如果网站支持IE6 浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 bank.example 域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。
- 即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。
在请求地址中添加 token 并验证
- CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。
- 要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token(令牌),并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
优点
- 这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对,但这种方法的难点在于如何把 token 以参数的形式加入请求。对于 GET 请求,token 将附在请求地址之后,这样 URL 就变成
http://url?csrftoken=tokenvalue
。 而对于 POST 请求来说,要在 form 的最后加上 ,这样就把 token 以参数的形式加入请求了。
缺点
- 但是,在一个网站中,可以接受请求的地方非常多,要对于每一个请求都加上 token 是很麻烦的,并且很容易漏掉,通常使用的方法就是在每次页面加载时,使用 javascript 遍历整个 dom 树,对于 dom 中所有的 a 和 form 标签后加入 token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的 html 代码,这种方法就没有作用,还需要程序员在编码时手动添加 token。
- 该方法还有一个缺点是难以保证 token 本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上 token,黑客可以在自己的网站上得到这个 token,并马上就可以发动 CSRF 攻击。为了避免这一点,系统可以在添加 token 的时候增加一个判断,如果这个链接是链到自己本站的,就在后面添加 token,如果是通向外网则不加。不过,即使这个 csrftoken 不以参数的形式附加在请求之中,黑客的网站也同样可以通过 Referer 来得到这个 token 值以发动 CSRF 攻击。这也是一些用户喜欢手动关闭浏览器 Referer 功能的原因。
在 HTTP 头中自定义属性并验证
- 这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
缺点
- 然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。
- 另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。
WAF防御CSRF
- 以上防御是技术层面的讨论。实际中进行 CSRF 防护的是使用 WAF(Web应用防火墙,如免费的ShareWAF)。因为 CSRF 只是众多web攻击中的一种,网络攻击还有很多种。WAF可以低于绝大多数的攻击,可极大的提高网站安全性。
评论