致力于自动化测试技术,性能测试技术的研究,测试技术培训以及项目实施,做一个技术与实施的主导者。

【转】浅谈CSRF攻击

上一篇 / 下一篇  2012-05-10 16:44:26 / 天气: 晴朗 / 心情: 平静 / 个人分类:安全性测试

51Testing软件测试网%DD4qN uPAS

一.CSRF是什么?51Testing软件测试网:j9S:LZE O

!LU_|l^a0  CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。51Testing软件测试网Whj8i2O

|l%D,l-Qh-|7x:k~R0二.CSRF可以做什么?

Pc_xs*L,~ Hc051Testing软件测试网 z+C ~X y O

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

:Y3Zg G#S1d`+A D0三.CSRF漏洞现状51Testing软件测试网hqK;C6Z T

51Testing软件测试网$U!TEOB6`

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

*aay3u0J/m'a"a051Testing软件测试网v@ jW+?c"V o

四.CSRF的原理

pW*|LX9{0

Jn? B'ChtEcB0  下图简单阐述了CSRF攻击的思想:

$Y~Z*~$^T"^0

:w*LU"o"c {-B&Jd g0  51Testing软件测试网R2rgcrR(W

v |aR%Ty+a#`0  从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤

9hR3s,k;Z6^ZI0

yy nL(i4\0i?0  1.登录受信任网站A,并在本地生成Cookie51Testing软件测试网%y3A r;a^4Wv$x

51Testing软件测试网3O7A5qI+W N

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

W-U b,`9X)rcl^051Testing软件测试网7R5MY~8JS rQ

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

7Dd#Ksr F`+l3I kl0

Ce$a0`"D7o-l%R0  1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。

1pi'N;_:Q051Testing软件测试网C p'@-w'y%}Q+k@`P6E

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

2}(@p~l_8Z"r051Testing软件测试网q3P(dS8lp

  3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。51Testing软件测试网$F0@ XL1|Zn8Kk

V#Cza^'O-T-S-_a0 

ZN1R2j]I0

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

Dx2[*`"QC!\.H0

B ?J|gw2g-n1|0  示例1:51Testing软件测试网)ni`5S,Wb N

j)~V}{d ~"]1E0  银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=100051Testing软件测试网+[$Z+j;bX TA

51Testing软件测试网[N_qIa

  危险网站B,它里面有一段HTML的代码如下:51Testing软件测试网)A,Q,Zn\T#Ba

  <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
51Testing软件测试网Zu rwl2E ^3e

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

)e xNs+QN0

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

/V:~ hrE6G0

-r"I-jS P5Y e RH u!y`*f0  示例2:51Testing软件测试网!{:M,eH0j'Kn/DT4x

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

{m Y W+d1b051Testing软件测试网$e _&E}G+Y3[kZ

  银行网站A的WEB表单如下:  51Testing软件测试网n9a-bD4K~

  <form action="Transfer.php" method="POST">51Testing软件测试网#D^`$r5rjwR!B
    <p>ToBankId: <input type="text" name="toBankId" /></p>51Testing软件测试网 MI\v-H Nc
    <p>Money: <input type="text" name="money" /></p>51Testing软件测试网 I1u{`.r+Y$w:j6S
    <p><input type="submit" value="Transfer" /></p>
/PU+@5^S-qPS0
  </form>51Testing软件测试网6n5\7X W$nmR8sk
51Testing软件测试网x]n t;Gn

  后台处理页面Transfer.php如下:51Testing软件测试网^1Jb(@6@:G3Fpt%|

复制代码
  <?php51Testing软件测试网 f/di A,K
    session_start();51Testing软件测试网5ot] W2]-A,{G
    if (isset($_REQUEST['toBankId'&& isset($_REQUEST['money']))51Testing软件测试网wd7N;v%]5}|
    {51Testing软件测试网_ ^}'g,BM
        buy_stocks(
$_REQUEST['toBankId'], $_REQUEST['money']);
o S+T I'eQ+F)a+o j0    }51Testing软件测试网Fj6j"Vu*uz
  ?>51Testing软件测试网'm!U7I }*| WKt h.F*Q
复制代码
51Testing软件测试网1r{3^E_IX.?!ve

  危险网站B,仍然只是包含那句HTML代码:51Testing软件测试网er5U;WS R~%w

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

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

51Testing软件测试网QM-v(s V+Gi

  示例3:

_ u]Mj\|0

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

)Ruw&V8s;y#O0
复制代码
  <?php
Lt1E W9xRk:S0    
session_start();51Testing软件测试网/{ h:Z0Tir0k
    
if (isset($_POST['toBankId'&& isset($_POST['money']))
6E Qq(_|0    {
)IpY&zV {0        buy_stocks(
$_POST['toBankId'], $_POST['money']);
j:u4C&B s P0    }51Testing软件测试网3E A7y(fB of
  
?>
@S%_i m-X6F%F KD0
复制代码

x!Vpk}:\0  然而,危险网站B与时俱进,它改了一下代码:

?1Uq!Bq[$H xa.E0
复制代码
<html>
Aq j$KJzZbH [0
  <head>
+e(aI*R7rKX7v+E%q0
    <script type="text/javascript">51Testing软件测试网%q aqmB;Hr3a9H
      function steal()51Testing软件测试网n r-da r;W sI
      {51Testing软件测试网mN&V)n ?&aE3mC
               iframe 
= document.frames["steal"];51Testing软件测试网+l`,P U7A{i
               iframe.document.Submit(
"transfer");
MhM$ktm6~ \Sm5Z-T0      }
qJ6hI1F|#nK5v0
    </script>51Testing软件测试网t@2P T5v-RH_{
  </head>51Testing软件测试网$I5R:Y7sH9y+Af\

JF3Y Nv;@4E0  
<body onload="steal()">
?4V-B;Q4c7F2B0
    <iframe name="steal" display="none">51Testing软件测试网7ZrJ9cG4u$Ts
      <form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">51Testing软件测试网G Q)i a]2S`
        
<input type="hidden" name="toBankId" value="11">51Testing软件测试网i\Z3v @0\|
        
<input type="hidden" name="money" value="1000">
iK(ev9OR@r[0      
</form>
Y)gG6w&XMY5n0
    </iframe>51Testing软件测试网hH(m UA:r.]
  </body>51Testing软件测试网Y^l*|.l:kZ3_
</html>51Testing软件测试网gq^:_Q/pBnYL
复制代码
51Testing软件测试网qU1^r"W;e2q

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

5j`Cc,p,l051Testing软件测试网!\#w1Q p)X?7ZQ C:[

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

51Testing软件测试网%g&Uwn$_"s[u

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

hBl7v [@A~ A)[A0

f~b.hv0五.CSRF的防御

6L]fa-EJ051Testing软件测试网r9w)I K1?-e~

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

R p C'O)T/M+S#@6a}O0

N8h1|+R L0P+\0  1.服务端进行CSRF防御

3W&du f KMl051Testing软件测试网cwE.y,X(U|

  服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数51Testing软件测试网Z&N(N?|){

51Testing软件测试网t&Pevx3g9m)C

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

`i[t Ph051Testing软件测试网Pw-]Ma@m

  这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>51Testing软件测试网?w*I4x5` [%L

  <?php
i/hj%A{6Ga G0
    //构造加密的Cookie信息51Testing软件测试网#c1uD!q @ ef`:U4W
    $value = “DefenseSCRF”;51Testing软件测试网'aPd1Z&a3k[
    setcookie(”cookie”, $value, time()+3600);51Testing软件测试网5jz,]hhdB:p
  ?>
Q]A L"PVh5f0

[/^#L;Q$Bz0  在表单里增加Hash值,以认证这确实是用户发送的请求。51Testing软件测试网sF;\!W CN:iO`

复制代码
  <?php51Testing软件测试网I g;pE:c$]mn2g
    $hash = md5($_COOKIE['cookie']);
g!BcNx*HPum7|0
  ?>
L iH#o9l0Y6J6h0
  <form method=”POST” action=”transfer.php”>51Testing软件测试网1i-W'\|#P8u(g/S
    <input type=”text” name=”toBankId”>
.I&l'py$]V"H0
    <input type=”text” name=”money”>51Testing软件测试网 Q"n3q8I:{\(?xl
    <input type=”hidden” name=”hash” value=<?=$hash;?>>51Testing软件测试网C3aV)k)h6A)n+Gy
    <input type=”submit” name=”submit” value=”Submit”>51Testing软件测试网b PgtL
  </form>
复制代码
51Testing软件测试网_qy7o1hk*?

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

D n$NrC\0
复制代码
      <?php51Testing软件测试网&j+T9UYk
       if(isset($_POST['check'])) {51Testing软件测试网}/Uy]O
            
$hash = md5($_COOKIE['cookie']);51Testing软件测试网hB}:EB)k/g2r^
            if($_POST['check'== $hash) {
J@(R3{#u-K1P N0                  doJob();51Testing软件测试网rd)q? xa9o
             } 
else {51Testing软件测试网 YA9T ]r F5r!o
        //...
51Testing软件测试网6HFRi"{m"H
             }51Testing软件测试网1n-i4R^V)q
        } 
else {51Testing软件测试网$Y Up!TKdx fA,]
      //...

9{Yv7d7T6w0        }51Testing软件测试网.OIo2VTB
      
?>
复制代码

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

/@)w5@j2yE1j6d"OG051Testing软件测试网7f,E6F5FK/I6J

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

D?.F2T(x4Dd!Q@z6J051Testing软件测试网+{/J:no2I6z*P$z$l

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

,z,b:}7Ch,o_%g051Testing软件测试网.GU8[6v1Lk,I

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

51Testing软件测试网 O l Sf&V@ y(h

  以下我的实现:

4}Gf,z?4z IK0

r)M _E6S5iW4v0  1).先是令牌生成函数(gen_token()):51Testing软件测试网$g,BYP*A

复制代码
     <?php51Testing软件测试网b"G&^|MOJ
     function gen_token() {
rkwXO ~"[0
    //这里我是贪方便,实际上单使用Rand()得出的随机数作为令牌,也是不安全的。51Testing软件测试网eoCE5h;O(t;[
    //这个可以参考我写的Findbugs笔记中的《Random object created and used only once》
J2w Z#_,?W@0
          $token =md5(uniqid(rand(), true));
YG(hvZ6F0          
return $token;51Testing软件测试网 z\)t(v nZ#p.n
     }
复制代码

B8|6f;JFRG6[0  2).然后是Session令牌生成函数(gen_stoken()):51Testing软件测试网7`Q)WN%o@4WY+F

复制代码
     <?php51Testing软件测试网q&i}cK0VbN t
     
  function gen_stoken() {
Z)E bS JY0
      $pToken = "";51Testing软件测试网2\$T;eZ(}
      if($_SESSION[STOKEN_NAME]  ==$pToken){
+S!D lK,^Ka0        //没有值,赋新值51Testing软件测试网q'H2p\E(D
      
  $_SESSION[STOKEN_NAME] =gen_token();51Testing软件测试网%w r LV^#x c{
      }   
k\Zo q!?9}0      else{
4w!YE!_)G4h/Pz0        //继续使用旧的值
0{@X"L'K4`;Ulk0      }
51Testing软件测试网\ xZ#KE%]2O~
       }
"\-E+aE8IN oFk0     
?>
复制代码
51Testing软件测试网,N OP,bL9E,czQ7w

  3).WEB表单生成隐藏输入域的函数:  51Testing软件测试网%_%~*]+U:d cWI7N2{%Hm

复制代码
     <?php51Testing软件测试网|K-eR%j%sV(Mt
       function gen_input() {
7|&PeS2o&r5Y6\&i H0            gen_stoken();
J4j/H,K8c9q8}0            echo “<input type=\”hidden\” name=\”" . FTOKEN_NAME . “\”51Testing软件测试网c o_Vx m
                 value=\”" . $_SESSION[STOKEN_NAME] . “\”> “;
D*]9])AV$o?0       }51Testing软件测试网y2I$_ `r&d:i ^![T
     ?>51Testing软件测试网 k\7o)?,^6bm
复制代码
51Testing软件测试网;C xE RT9jf/J

  4).WEB表单结构:

t,i OB;@0
复制代码
    <?php51Testing软件测试网m[5y*\-H3Cq
          
session_start();51Testing软件测试网@0t,i eRc}
          
include(”functions.php”);
FoJD;u:P'V`~*Z K0     
?>
1{@,P2iR|0     
<form method=”POST” action=”transfer.php”>
$J+Nwr6ap?0          
<input type=”text” name=”toBankId”>
vh3aw3F~(j#E&N0          
<input type=”text” name=”money”>
-h.p!g5n m4?N.^0          
<? gen_input(); ?>51Testing软件测试网)d P9YpCS/m
          
<input type=”submit” name=”submit” value=”Submit”>
^yp~1V O%[+i?+p]0     
</FORM>
复制代码

\8z+vs0W.w4B y0  5).服务端核对令牌:51Testing软件测试网JMI0_+\;^u

51Testing软件测试网 ~4UrX5F|)x _o

  这个很简单,这里就不再啰嗦了。51Testing软件测试网Sd6kq9G#~$T!tH

51Testing软件测试网.F3s~HH-\X

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

_.^qBw051Testing软件测试网.UD!QJ(A7r#g,pc

转自好友博客:http://www.cnblogs.com/hyddd/51Testing软件测试网'D8{(G)u3|

#G*G \4`'y1EZk ~ A051Testing软件测试网8]FD W-vW _

#b%dTot&[/})`5]0

TAG:

 

评分:0

我来说两句

vprince

vprince

6年软件测试经验,TIB自动化测试工作室核心成员,ATF框架核心设计和开发人员,熟悉软件自动化测试、性能测试,多年从事软件项目的自动化测试和性能测试,对自动化测试的框架设计开发、框架搭建以及实施有较为丰富的实战经验。 目前关注开源自动化测试领域、 基于Selenium构建Web自动化测试框架,为多家企业进行自动化测试培训、实施自动化测试项目。

日历

« 2024-04-11  
 123456
78910111213
14151617181920
21222324252627
282930    

数据统计

  • 访问量: 67281
  • 日志数: 49
  • 建立时间: 2009-09-09
  • 更新时间: 2012-12-14

RSS订阅

Open Toolbar