浅谈CSRF攻击方式

703 阅读17分钟
原文链接: www.cnblogs.com
代码改变世界

hyddd 知行合一

浅谈CSRF攻击方式

2009-04-09 22:44 by hyddd, 274634 阅读, 128 评论, 收藏, 编辑

一.CSRF是什么?

  CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。

二.CSRF可以做什么?

  你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。

三.CSRF漏洞现状

  CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到06年才开始被关注,08年,国内外的多个大型社区和交互网站分别爆出CSRF漏洞,如:NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站),YouTube和百度HI......而现在,互联网上的许多站点仍对此毫无防备,以至于安全业界称CSRF为“沉睡的巨人”。

四.CSRF的原理

  下图简单阐述了CSRF攻击的思想:

  

  从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1.登录受信任网站A,并在本地生成Cookie。

  2.在不登出A的情况下,访问危险网站B。

  看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

  1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。

  2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)

  3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

 

  上面大概地讲了一下CSRF攻击的思想,下面我将用几个例子详细说说具体的CSRF攻击,这里我以一个银行转账的操作作为例子(仅仅是例子,真实的银行网站没这么傻:>)

  示例1:

  银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000

  危险网站B,它里面有一段HTML的代码如下:

  <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000 >

  首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块......

  为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“http://www.mybank.com/Transfer.php?toBankId=11&money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作......

  示例2:

  为了杜绝上面的问题,银行决定改用POST请求完成转账操作。

  银行网站A的WEB表单如下:  

  <form action="Transfer.php" method ="POST">
    <p> ToBankId: <input type="text" name ="toBankId" /></p>
    <p>Money: <input  type="text" name="money" /></ p>
    <p>< input type="submit" value=" Transfer" /></p >
  </form>

  后台处理页面Transfer.php如下:

  <?php
    session_start();
    if  (isset($_REQUEST[' toBankId'] && isset ($_REQUEST['money' ]))
    {
        buy_stocks($_REQUEST[' toBankId'], $_REQUEST ['money']);
    }
  ?>

  危险网站B,仍然只是包含那句HTML代码:

  <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000 >

  和示例1中的操作一样,你首先登录了银行网站A,然后访问危险网站B,结果.....和示例1一样,你再次没了1000块~T_T,这次事故的原因是:银行后台使用了$_REQUEST去获取请求的数据,而$_REQUEST既可以获取GET请求的数据,也可以获取POST请求的数据,这就造成了在后台处理程序无法区分这到底是GET请求的数据还是POST请求的数据。在PHP中,可以使用$_GET和$_POST分别获取GET请求和POST请求的数据。在JAVA中,用于获取请求数据request一样存在不能区分GET请求数据和POST数据的问题。

  示例3:

  经过前面2个惨痛的教训,银行决定把获取请求数据的方法也改了,改用$_POST,只获取POST请求的数据,后台处理页面Transfer.php代码如下:

  <?php
    session_start();
     if (isset($_POST[ 'toBankId'] &&  isset($_POST['money ']))
    {
        buy_stocks($_POST[' toBankId'], $_POST ['money']);
    }
  ?>

  然而,危险网站B与时俱进,它改了一下代码:

<html>
  < head>
    <script  type="text/javascript">
      function  steal()
      {
               iframe = document.frames[ "steal"];
               iframe.document.Submit( "transfer");
      }
    </script>
  </head >

  <body onload ="steal()">
    < iframe name="steal" display="none" >
      <form method ="POST" name="transfer" action="http://www.myBank.com/Transfer.php" >
        <input type ="hidden" name="toBankId" value="11" >
        <input type ="hidden" name="money" value ="1000">
      </ form>
    </iframe >
  </body>
</html>

如果用户仍是继续上面的操作,很不幸,结果将会是再次不见1000块......因为这里危险网站B暗地里发送了POST请求到银行!

  总结一下上面3个例子,CSRF主要的攻击模式基本上是以上的3种,其中以第1,2种最为严重,因为触发条件很简单,一个<img>就可以了,而第3种比较麻烦,需要使用JavaScript,所以使用的机会会比前面的少很多,但无论是哪种情况,只要触发了CSRF攻击,后果都有可能很严重。

  理解上面的3种攻击模式,其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!

五.CSRF的防御

  我总结了一下看到的资料,CSRF的防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。

  1.服务端进行CSRF防御

  服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。

  (1).Cookie Hashing(所有表单都包含同一个伪随机值):

  这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>

  <?php
    //构造加密的Cookie信息
    $value = “DefenseSCRF”;
    setcookie(”cookie” , $value, time ()+3600);
  ?>

  在表单里增加Hash值,以认证这确实是用户发送的请求。

  <?php
    $hash  = md5($_COOKIE[' cookie']);
  ?>
  < form method=”POST” action=”transfer. php”>
    <input type= ”text” name=”toBankId”>
    < input type=”text” name=”money” >
    <input type=”hidden” name =”hash” value=”<?=$hash ;?>”>
    < input type=”submit” name=”submit” value =”Submit”>
  </ form>

  然后在服务器端进行Hash值验证

      <?php
        if(isset($_POST[' check'])) {
             $hash  = md5($_COOKIE[ 'cookie']);
           if($_POST['check '] == $hash) {
                  doJob();
             }  else {
        //...
           }
        }  else {
      //...
        }
       ?>

  这个方法个人觉得已经可以杜绝99%的CSRF攻击了,那还有1%呢....由于用户的Cookie很容易由于网站的XSS漏洞而被盗取,这就另外的1%。一般的攻击者看到有需要算Hash值,基本都会放弃了,某些除外,所以如果需要100%的杜绝,这个不是最好的方法。  (2).验证码

  这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,厄....这个方案可以完全解决CSRF,但个人觉得在易用性方面似乎不是太好,还有听闻是验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

  (3).One-Time Tokens(不同的表单包含一个不同的伪随机值)

  在实现One-Time Tokens时,需要注意一点:就是“并行会话的兼容”。如果用户在一个站点上同时打开了两个不同的表单,CSRF保护措施不应该影响到他对任何表单的提交。考虑一下如果每次表单被装入时站点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况:用户只能成功地提交他最后打开的表单,因为所有其他的表单都含有非法的伪随机值。必须小心操作以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。

  以下我的实现:

  1).先是令牌生成函数(gen_token()):

     <?php
      function gen_token() {
    //这里我是贪方便,实际上单使用Rand()得出的随机数作为令牌,也是不安全的。
    //这个可以参考我写的Findbugs笔记中的《Random object created and used only once》
           $token = md5( uniqid(rand(),  true));
          return  $token;
     }

  2).然后是Session令牌生成函数(gen_stoken()):

     <?php
       function  gen_stoken() {
      $pToken = "";
      if($_SESSION[STOKEN_NAME]  == $pToken ){
        //没有值,赋新值
        $_SESSION[STOKEN_NAME] = gen_token();
      }   
      else{
        //继续使用旧的值
      }
       }
     ?>

  3).WEB表单生成隐藏输入域的函数:  

     <?php
       function gen_input() {
            gen_stoken();
            echo “<input type=\”hidden\” name=\”" . FTOKEN_NAME . “\”
                 value=\”" . $_SESSION[STOKEN_NAME] . “\”> “;
       }
     ?>

  4).WEB表单结构:

     <?php
          session_start ();
          include(”functions.php”);
      ?>
     <form method= ”POST” action=”transfer.php”>
          <input type= ”text” name=”toBankId”>
           <input type=”text” name= ”money”>
           <? gen_input(); ?>
           <input type=”submit” name= ”submit” value=”Submit”>
      </FORM>

  5).服务端核对令牌:

  这个很简单,这里就不再啰嗦了。

  上面这个其实不完全符合“并行会话的兼容”的规则,大家可以在此基础上修改。

 

  其实还有很多想写,无奈精力有限,暂且打住,日后补充,如果错漏,请指出:>

  PS:今天下午写这篇文档的时候FF崩溃了一次,写了一半文章的全没了,郁闷好久T_T.......

  转载请说明出处,谢谢[hyddd(http://www.cnblogs.com/hyddd/)]

六.参考文献

[1].Preventing CSRF

[2].Security Corner: Cross-Site Request Forgeries

[3].《深入解析跨站请求伪造漏洞:原理剖析》

[4].《Web安全测试之跨站请求伪造(CSRF)》

[5].《深入解析跨站请求伪造漏洞:实例讲解》

[6].http://baike.baidu.com/view/1609487.htm

 

 

作者:hyddd
出处:www.cnblogs.com/hyddd/
本文版权归作者所有,欢迎转载,演绎或用于商业目的,但是必须说明本文出处(包含链接)。

< Prev12 3 Add your comment

  1. #101楼 吃藕chou   2016-11-10 14:33
    厉害了 我的哥 支持(0)反对(0) http://pic.cnblogs.com/face/867778/20151228151823.png
  2. #102楼 hyber   2016-11-19 00:01
    相当感谢 支持(1)反对(0) http://pic.cnblogs.com/face/1044608/20161017224917.png
  3. #103楼 monkey's   2016-11-20 20:47
    厉害了 我的哥 支持(0)反对(0) http://pic.cnblogs.com/face/u305497.jpg?id=27231910
  4. #104楼 程序小工   2017-01-03 10:22
    厉害了 我的哥 支持(0)反对(0) http://pic.cnblogs.com/face/1049028/20180329171718.png
  5. #105楼 Tiac   2017-01-04 14:51
    学习了 支持(0)反对(0) http://pic.cnblogs.com/face/550797/20160308143819.png
  6. #106楼 画银堂   2017-01-04 15:22
    楼主写得很好,学习了 支持(1)反对(0)
  7. #107楼 lulianqi15   2017-01-11 15:25
    虽然 不知道是不是 以前浏览器都是请求时可以把所有域的cookie带上,不过现在到其他页面,已经取不出属于其他域的cookie,上面的说法都不成立。这种跨域攻击已经被浏览器规避了。 支持(0)反对(4) http://pic.cnblogs.com/face/209007/20150914192924.png
  8. #108楼 俊俊民   2017-01-12 20:57
    好棒!希望大大继续写~ 支持(0)反对(0)
  9. #109楼 有酱油卖吗   2017-02-09 00:53
    你好,我在使用ajax 登录的时候 吧token的值写在了header 里面 ,但是我后台filter的时候 验证这个header和cookie值的时候, 他们一直不一样,连cookie值和前台的hidden 标签的值都不一样 是怎回事呀?求解(我这里是ajax提交) 支持(0) 反对(0) http://pic.cnblogs.com/face/831480/20160614144607.png
  10. #110楼[楼主] hyddd   2017-02-23 18:19
    @ lulianqi15
    理解有问题,攻击并不是这样。 支持(0)反对(0) http://pic.cnblogs.com/face/u46057.png
  11. #111楼 妮妮爸   2017-03-03 15:19
    写的真是太好了 支持(0)反对(0)
  12. #112楼 miao933   2017-03-15 16:58
    感谢分享 支持(0)反对(0)
  13. #113楼 coder_jason   2017-05-05 14:06
    @ lulianqi15
    回复 107 楼

    带有的攻击的网站根本就不需要你的cookie啊
    A(目标网站) B(攻击网站)
    比如 - B <img src="A站的url">
    你去加载 B的时候 需要请求 这个img的url
    也就是你自己会请求 A的url(A当然可以获取你在A的所有cookie)
    就相当于你 再一次请求 A (但是这个请求不是你自愿的,你只是请求了B,没想过再一次请求A) 支持(2)反对(0)
  14. #114楼 swing07   2017-05-06 14:37
    LZ 登录A网站, 打开B网站 B中包含src到B网站的请求,能把A网站的cookie带过去,这个看了你的才知道,这个感觉是不是浏览器的bug啊? 支持(0)反对(4) http://pic.cnblogs.com/face/485485/20160826174008.png
  15. #115楼 JuFoFu   2017-05-22 02:57
    文章写的很好,十分感谢楼主的分享~看完后有两点疑问:
    1、CSRF的防御的第一种方法为什么不在服务器做用户身份信息加密混淆生成token的方式?cookie是在浏览器端的数据,有盗取风险;MD5只是一个混淆算法,很容易模拟。而且用户通过XSS漏洞获取到了cookie已经能够脱离CSRF攻击方式而进行中间人攻击了。
    2、第三种防御方式在有XSS漏洞的情况下其实和第一种方式一样面临被盗取的风险,只要页面上生成的token不失效,攻击者也能直接盗取页面上的token通过验证。感觉本质上并没有提升安全性,只是提升了攻击的复杂度。
    期待楼主抽空解惑,谢谢~ 支持(2)反对(0) http://pic.cnblogs.com/face/739151/20150402091140.png
  16. #116楼 黄土地上的黑石头   2017-06-28 16:49
    我能膜拜一下么 支持(0)反对(0) http://pic.cnblogs.com/face/1114374/20170227154903.png
  17. #117楼 AzzStyle   2017-06-29 12:27
    @ JuFoFu
    csrf的第一种防御明显存在很大漏洞。
    正如层主所述,生成的token必须要根据当前登录用户的身份信息做混淆才能起到防御的作用。 支持(0)反对(0) http://pic.cnblogs.com/face/u471763.jpg?id=05120118
  18. #118楼 岩小黑   2017-09-08 11:18
    @ JuFoFu
    如果将关键cookie设为HttpOnly的话就能极大的避免XSS攻击,这样就能避免攻击者进行中间人攻击了 支持(0)反对(0)
  19. #119楼 故事细腻icon   2017-09-26 16:19
    这个可以通过referer控制吗 只有请求来自本站才接受 支持(0)反对(0)
  20. #120楼 zhu_jinlong   2017-11-07 13:48
    @ swing07
    不是打开 “打开B网站 B中包含src到B网站的请求”, src仍然是到A网站的 支持(0)反对(0)
  21. #121楼 zhu_jinlong   2017-11-07 13:51
    文章写得非常好 支持(0)反对(0)
  22. #122楼 zhu_jinlong   2017-11-07 13:53
    @ lulianqi15
    不可能把所有域的cookie都带上的,如果用户登录过n个网站,就会有n个cookie,然后访问某一个网站,都带上这么多cookie? cookie的附带遵守同源策略。 支持(0) 反对(0)
  23. #123楼 大官人的博客   2017-11-16 19:53
    博客园的验证码也是使用的geetest,不过登录框有点丑,哈。楼主写的很受用,学习了,个人看过多篇文章自己理解加总结了一篇,还请赐教,<a href="daguanren.cc/post/csrf-i…">click me</a> 支持(0)反对(0)
  24. #124楼 天尽头的那片海   2017-11-29 16:35
    厉害了 我的哥 支持(0)反对(0)http://pic.cnblogs.com/face/826791/20160105153405.png
  25. #125楼 atjinna   2017-12-07 13:57
    你好,感谢分享,我转载了此文了,也在注明出处了 ^^ 支持(0)反对(0)http://pic.cnblogs.com/face/1046492/20170601154147.png
  26. #126楼 ShiveryMoon   2017-12-21 13:21
    很好,感谢 支持(0)反对(0)http://pic.cnblogs.com/face/1273209/20171106103408.png
  27. #127楼 喝着啤酒写bug   2018-01-29 20:52
    虽然不是java版本, 但万变不离其中,写得通谷易通,赞一个! 支持(0)反对(0)http://pic.cnblogs.com/face/1128579/20171007180300.png
  28. #128楼39129992018/3/1 0:05:25 ZVIT   2018-03-01 00:05
    感谢分享,好文章 支持(0)反对(0)
< Prev12 3 刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录注册访问网站首页。 【推荐】超50万VC++源码: 大型组态工控、电力仿真CAD与GIS源码库!
【推荐】华为云11.11普惠季 血拼风暴 一促即发
【拼团】腾讯云服务器拼团活动又双叒叕来了!
【推荐】腾讯云新注册用户域名抢购1元起
腾讯云1008 最新IT新闻:
· Redis 5.0正式发布
· 盖茨:别把AI风险看太重 防儿童患疟疾这事更重要
· 科学第一巨奖突破奖颁发:庄小威陈志坚许晨阳上榜
· 谷歌详解Pixel 3系列安全芯片Titan M
· 10nm工艺难产:Intel制造业务将一分为三
» 更多新闻... 最新知识库文章:
· 阿里云的这群疯子
· 为什么说 Java 程序员必须掌握 Spring Boot ?
· 在学习中,有一个比掌握知识更重要的能力
· 如何招到一个靠谱的程序员
· 一个故事看懂“区块链”
» 更多知识库文章...

About

hyddd

Hi,我是hyddd(陈曦明),毕业于吉林大学,就职于多玩,带领团队从事内部系统与自动化测试平台研发。有任何问题,可以邮件与我联系,欢迎学习交流。

Hi, I'm ChenXiming. A programmer from YY.Inc, base on GuangZhou,China. If you want to get in touch with me, send the email.

知识共享许可协议:本站作品由hyddd创作,欢迎转载,演绎或用于商业目的,但是必须说明作品出处(包含链接)。

想更一进步的支持我,请扫描下方的二维码,你懂的~

  我的新浪微博 订阅我的博客  订阅我的博客 昵称:hyddd
园龄:9年10个月
粉丝:1459
关注:3 +加关注

最新随笔

最新评论

随笔档案

日历

< 2009年4月 >
29 30 31 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 1 2
3 4 5 6 7 8 9

我的标签

随笔分类

推荐排行榜

阅读排行榜

www.spiga.com.mx

Copyright ©2018 hyddd

博客园