欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

浅谈CSRF攻击方式

浅谈CSRF攻击方式

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

一.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的代码如下:

  首先,你登录了银行网站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代码:

  和示例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
出处:http://www.cnblogs.com/hyddd/
本文版权归作者所有,欢迎转载,演绎或用于商业目的,但是必须说明本文出处(包含链接)。

 
70
0
 
 
 
« 上一篇:浅谈HTTP中Get与Post的区别
» 下一篇:【转】2008年.Net编程人员工具参照
Add your comment

 

 
  1. #51楼 神不倦我   2014-07-16 16:09
    \<script\>alert(\"感觉不错的样子!\")\</script\>
     
  2. #52楼 你好~八月   2014-08-25 16:00
    <script>alert('xsssss')</script>
     
  3. #53楼 叉叉哥   2014-09-03 14:55
    楼上的两个小伙伴想XSS攻击博客园吗?
    文章不错,顶一下!
     
  4. #54楼 小静(Cathy)   2014-09-16 09:41
    好文要顶,学习了
     
  5. #55楼 弹痕   2014-10-16 11:08
    <script>alert('xsssss')</script>
     
  6. #56楼 hexllo   2014-12-03 15:18
    <script>
     
  7. #57楼 颜海镜   2014-12-29 16:40
    涨姿势了
     
  8. #58楼 agang_19   2015-01-27 09:53
    <script>alert("xss")</script>
     
  9. #59楼 Smile-2014   2015-01-28 15:58
    <>
     
  10. #60楼 Smile-2014   2015-01-28 16:01
    </div><div><iframe src="xxx" weight="960" height="400"></iframe>
     
  11. #61楼 Smile-2014   2015-01-28 16:03
    \*<iframe*\
     
  12. #62楼 Smile-2014   2015-01-28 16:05
    &lt;div id='s'&gt; 
    test 
    &lt;/div&gt; 
    &lt;script&gt; 
    var s = "u003cimg src=1 onerror=alert(/xss/)u003e"; 
    document.getElementById('s').innerHTML = s; 
    &lt;/script&gt;
     
  13. #63楼 inevermore   2015-03-30 14:27
    学习了
     
  14. #64楼 naraku666   2015-04-15 08:49
    @ 叉叉哥
    为什么前面两个都没用的,我也直接设置innerHTML也不会触发哦
     
  15. #65楼 女孩不哭   2015-04-21 18:13
    这么多人想攻击博客园啊?
    在输出评论之前全部实体化html标签,看你们闹。
     
  16. #66楼 Jack Su Sparrow   2015-06-26 10:59
    Marked
     
  17. #67楼 sustudy   2015-07-08 13:38
    好文章,思路清晰明了
     
  18. #68楼 cart55free99   2015-07-28 12:59
    访问危险网站B 的请求为什么会有网站A的 cookie
     
  19. #69楼 koi   2015-08-04 10:28
    mark
     
  20. #70楼 digdeep   2015-08-05 09:56
     
  21. #71楼 digdeep   2015-08-05 10:01
    <a href="http://www.baidu.com/csrf.html">click me</a>
     
  22. #72楼 萝卜小兔子头   2015-09-11 12:02
    <script>alert("xss")</script>
     
  23. #73楼 AzzStyle   2015-09-18 22:04
    $_POST['check'] 是啥?
     
  24. #74楼 _leon   2015-10-05 20:35
    博主,第二点客户端怎么防范呢?
     
  25. #75楼 zzzp0755   2015-10-12 10:27
    基本上可以杜绝CSRF,不过如果是抓包的话,会得到你token值,一样可以模拟你转账的操作
     
  26. #76楼[楼主] hyddd   2015-10-12 20:13
    @ zzzp0755
    你说的是man in middle,完全2回事了。交互流程如上图的才叫CSRF。而防止man in middle这种问题,需要数据加密和数据校验,如:SSL...。而以转款为例子,man in middle抓住的问题的本质缺陷是:明文数据或者数据可篡改。坦白说,对于非ssl传输的数据,man in middel这种做法可以有很多玩法,如:监听并获取他人cookies(sessionid),然后贴到自己浏览器的cookies上模拟别人登陆,多简单.......但前提你要入侵路由。当然,局域网玩这个是容易的,所以出外的核心数据访问,要么先vpn,要么自带4G路由....man in middel国家对还是业余队都是没少干的事情....
     
  27. #77楼 梦流星   2015-11-06 17:08
    %3Cscript%3Ealert%28%22helloxxs%22%29%3B%3C%2Fscript%3E
     
  28. #78楼 梦流星   2015-11-07 00:07
    这个地方评论是用ajax加载的.....
     
  29. #79楼 黑翼天使23   2015-11-28 21:59
    好文章,mark!
     
  30. #80楼 tinyphp   2015-12-15 15:45
    有用!
     
  31. #81楼 yunpeng   2016-01-25 16:21
    好文要顶
     
  32. #82楼 Jerry.Chin   2016-02-17 17:11
    好文要顶!
     
  33. #83楼 譬如北辰   2016-02-23 11:04
     
  34. #84楼 wqdjl   2016-02-26 15:10
     
  35. #85楼 laden666666   2016-03-04 11:53
    写xss攻击的小伙伴们是在卖萌吗?
     
  36. #86楼 FORWARDBA   2016-03-17 19:28
    彻底明白CSRF这个东西了,
    感谢楼主。
     
  37. #87楼 NewSea   2016-03-19 21:25
    mark.
     
  38. #88楼 melody_崔   2016-04-01 16:52
    token一定要放到表单中,然后请求时做为参数传过来么。可不可以放到session中,服务器在处理请求前从session中拿出来进行验证。
     
  39. #89楼 tying   2016-04-06 10:17
    @ cart55free99
    没有拿到cookie呀,你登陆了邮箱,然后关闭浏览器窗口的选项卡,在历史记录里面再次打开刚刚关闭的选项卡,不会让你在从新登陆一遍的
     
  40. #90楼 zoey_717   2016-04-21 16:22
    大赞
     
  41. #91楼 乔布儿   2016-04-23 08:49
    当初有一片好文章摆在我的面前我没有珍惜,等到被攻击了才后悔莫急.
     
  42. #92楼 PmPen   2016-06-21 12:14
    xxx
     
  43. #93楼 PmPen   2016-06-21 12:15
    x111xx
     
  44. #94楼 Feng_zhulin   2016-07-01 15:17
    nice mark
     
  45. #95楼 sirding   2016-07-28 14:48
    貌似一个token就搞定了很多问题
     
  46. #96楼 loosen_qian   2016-08-16 22:09
    在CSRF的规避方案有点困惑,博主讲的第一个防御方案是对构造加密的cookie,并且说因为攻击者不能获得第三方的Cookie(理论上),那么既然Cookie是第三方不能获取的,为什么之前讲解CSRF原理时,webB可以获取user的cookie进而伪造请求??

    来自  http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html

普通分类: