CSRF/XSRF概述

概述

CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,一般是攻击者冒充用户进行站内操作,它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则是伪装成受信任用户的请求来访问操作受信任的网站。

原理

CSRF攻击经常利用目标站点的身份验证机制,CSRF攻击这一弱点的根源在于Web的身份验证机制虽然可以向目标站点保证一个请求来自于经过站点认证的某个用户的账号,但是却无法保证该请求的确是那个用户发出的或者是经过那个用户批准的。
目前web网站泛用的身份验证机制就是cookie-session认证机制,来跟踪记录用户的行为。
CSRF攻击依赖下面的假定:
攻击者了解受害者所在的站点;
攻击者的目标站点具有持久化授权cookie或者受害者具有当前会话cookie;
目标站点没有对用户在网站行为的第二授权;
欺骗用户的浏览器发送HTTP请求给目标站点(也就是忽悠用户点击攻击链接)或者攻击者控制部分or全部站点(比如攻击者通过XSS拿到未失效且经过网站授权的cookie)。
参考深入解析跨站请求伪造漏洞:原理剖析。
比如攻击者编写了一个在用户的银行站点上进行取款的form提交的链接,并将此链接作为图片src。如果用户的银行在cookie中保存他的授权信息,并且此cookie没有过期,那么当用户的浏览器尝试装载图片时将提交这个取款form和他的cookie,这样在没经用户同意的情况下便授权了这次转账。
如下图所示:
CSRF/XSRF概述_第1张图片常见威胁

1:通过邮件、图片链接骗取用户,如下html所示

创建图片链接: HTML 教程

含有CSRF攻击的图片,这种一般是get方式,有时需要提交表单,采用POST方式提交。此时构造个隐藏的HTML表单提交些数据过去就可以了。参考csrf的post攻击。

2:多窗口浏览器就帮了一点忙。
多窗口浏览器(firefox、遨游、MyIE……)便捷的同时也带来了一些问题,因为多窗口浏览器新开的窗口是具有当前所有会话的。单窗口浏览器IE就不会,如我用ie登陆了我的Blog,然后我想看新闻了,又运行一个IE进程,这个时候两个IE窗口的会话是彼此独立的,从看新闻的IE发送请求到Blog不会有我登录的cookie;但是多窗口浏览器永远都只有一个进程,各窗口的会话是通用的,即看新闻的窗口发请求到Blog是会带上我在blog登录的cookie。

案例

转载自csrf危害
案例一:

一个银行站点存在一个csrf漏洞,用户A转账给B用户2000元,执行转账操作后会对银行发送一次请求:“http://www.bank.com/money?user=A&num=2000&transfer=B”,然后A用户就会把自己的2000元转到B的账户下。在发送这个请求给银行服务器时,服务器首先会验证这个请求是否为一个合法的session,并且用户A确认登陆才可以验证通过。

如果此时有一个恶意用户C想把A用户的钱转到自己的账户下,那么他可以构造 http://www.bank.com/money?user=A&num=2000&transfer=C 这个请求,但是这个请求必须有A用户发出才可以生效,此时恶意用户C可以搭建一个自己的网站,在网站中写入如下代码 ,之后诱导A用户访问自己的网站,当A访问这个网站时,这个网站就会把img标签里的URL发给银行服务器,而此时除了这个请求以外,还会把A用户的cookie一起发到服务器,如果此时A用户的浏览器与银行的session没有过期,那么就会在A用户毫不知情的情况下执行转账给C的操作。

案例二:

一个cms系统的管理后台,可以发送一个post请求添加一个管理员,url为"http://www.cms.com/add", 由于没有加token或者验证码限制,恶意攻击者可以在自己的服务器evil.com上建立一个a.html的文件,a.html文件是一个添加管理员账户的表单,上面写入需要添加的账户用户名及密码,当网站管理员打开"evil.com/a.html"的时候,并且管理员的session没有失效,那么此时a.html就会请求受攻击网站,在管理员毫不知情的情况下添加一个后台账户。
a.html内容如下:

 
  • 通过以上两个案例可以得出结论,csrf会根据业务功能场景的不用而利用起来也不同,这些请求都是跨域发起的,而且是在受害者的session没有失效通过身份认证的情况下发生的。
  • 使用用户的登陆凭证,让用户自己在不知情的情况下,进行修改数据的操作。
  • 但是查询数据的地方却不需要保护,因为csrf是借助受害者的cookie来进行攻击者需要的恶意操作的,攻击者并不能拿到受害者cookie,对于服务器返回的结果也无法解析查看,攻击者唯一可以做的就是让服务器执行自己的操作命令,或者说改变网站数据,而查询操作即不会改变数据也不会把结果返回给攻击者,所以并不需要保护。

防护措施

对于web站点,将持久化的授权方法(例如cookie或者HTTP授权)切换为瞬时的授权方法(在每个form中提供隐藏field,如token),这将帮助网站防止这些攻击。
服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。

  1. 检查HTTP 头部 Refer 信息
    这是防止 CSRF 的最简单容易实现的一种手段。根据 RFC 对于 HTTP 协议里面 Refer 的定义,Refer 信息跟随出现在每个 Http 请求头部。Server 端在收到请求之后,可以去检查这个头信息,只接受来自本域的请求而忽略外部域的请求,这样就可以避免了很多风险。当然这种检查方式由于过于简单也有它自身的弱点:
  • 首先是检查 Refer 信息并不能防范来自本域的攻击。在企业业务网站上,经常会有同域的论坛,邮件等形式的 Web 应用程序存在,来自这些地方的 CSRF 攻击所携带的就是本域的 Refer 域信息,因此不能被这种防御手段所阻止。

  • 同样,某些直接发送 HTTP 请求的方式(指非浏览器,比如用后台代码等方法)可以伪造一些 Refer 信息,虽然直接进行头信息伪造的方式属于直接发送请求,很难跟随发cookie,但由于目前客户端手段层出不穷,flash,javascript 等大规模使用,从客户端进行 refer的伪造,尤其是在客户端浏览器安装了越来越多的插件的情况下已经成为可能了。

  1. Cookie Hashing(所有表单都包含同一个伪随机值)
    这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了,但由于网站中存在XSS漏洞而被偷窃的危险。

  2. 验证码
    这种方法的出现的作用是对于机器人暴力攻击的防止。但在 CSRF 的防范上,也有 一些 安全性要求比较高的的应用程序结合验证图片和一次性令牌来做双重保护。由于这种 图片验证信息很难被恶意程序在客户端识别,因此能够提高更强的保护。当客户端的浏览器可能已经处于一种不安全的环境中的情况下(比如客户端的安全级别设置较低,客户端浏览器安装了不安全的插件等)。但个人觉得在易用性方面似乎不是太好,还有听闻是验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

  3. One-Time Tokens(一次性令牌)

    一般通过session token来实现保护。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。接收到请求后,服务器端会对Token值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。
      在实现One-Time Tokens时,需要注意一点:就是“并行会话的兼容”。如果用户在一个站点上同时打开了两个不同的表单,CSRF保护措施不应该影响到他对任何表单的提交。考虑一下如果每次表单被装入时站点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况:用户只能成功地提交他最后打开的表单,因为所有其他的表单都含有非法的伪随机值。必须小心操作以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。
      另外,这里的session token机制也可用于注册或者cms文章添加等功能上,可以用来防止用户"重复提交",相比于上面的CSRF方案是这样的:服务器端第一次验证相同过后,会将涩session中的Token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。
      
    下面是tp3.2.3表单验证的代码(One-Time Tokens实现方法)

  • 表单
//表单



  
  • 表单验证(防csrf),可以看到利用session保存了token
//生成token代码省略
;;;;;
// 自动表单令牌验证
    public function autoCheckToken($data)
    {
        // 支持使用token(false) 关闭令牌验证
        if (isset($this->options['token']) && !$this->options['token']) {
            return true;
        }

        if (C('TOKEN_ON')) {
			
            $name = C('TOKEN_NAME', null, '__hash__');
		
            if (!isset($data[$name]) || !isset($_SESSION[$name])) {
                // 令牌数据无效	
		        $this->error='令牌数据无效';
                return false;
            }
      
            // 令牌验证
            list($key, $value) = explode('_', $data[$name]);			
			
            if (isset($_SESSION[$name][$key]) && $value && $_SESSION[$name][$key] === $value) {
                // 防止重复提交					
                unset($_SESSION[$name][$key]); // 验证完成销毁session
                return true;
            }
            // 开启TOKEN重置
            if (C('TOKEN_RESET')) {
                unset($_SESSION[$name][$key]);
            }
            $this->error='表单重复提交';
            return false;
        }
        return true;
    }
  • 验证经TP处理后的表单,可以看到生成了隐藏字段_hash_

CSRF/XSRF概述_第2张图片

你可能感兴趣的:(web安全)