1. 程式人生 > >CSRF,XSS攻擊與防禦

CSRF,XSS攻擊與防禦

 CSRF概念:CSRF跨站點請求偽造(Cross—Site Request Forgery),跟XSS攻擊一樣,存在巨大的危害性,你可以這樣來理解:
       攻擊者盜用了你的身份,以你的名義傳送惡意請求,對伺服器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義傳送郵件、發訊息,盜取你的賬號,新增系統管理員,甚至於購買商品、虛擬貨幣轉賬等。 如下:其中Web A為存在CSRF漏洞的網站,Web B為攻擊者構建的惡意網站,User C為Web A網站的合法使用者。

 

        CSRF攻擊攻擊原理及過程如下:

       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:

  銀行網站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

            1、提交驗證碼

                    在表單中新增一個隨機的數字或字母驗證碼。通過強制使用者和應用進行互動。來有效地遏制CSRF攻擊。

            2、Referer Check

                    檢查假設是非正常頁面過來的請求,則極有可能是CSRF攻擊。

            3、token驗證

                    (1)在 HTTP 請求中以引數的形式新增一個隨機產生的 token,並在伺服器端建立一個攔截器來驗證這個 token,假設請求中沒有 token 或者 token 內容不對,則覺得可能是 CSRF 攻擊而拒絕該請求。

                    (2)token必須足夠隨機

                    (3)敏感的操作應該使用POST,而不是GET。比如表單提交。

            4、在HTTP頭中自己定義屬性並驗證

                    這樣的方法也是使用 token 並進行驗證。這裡並非把 token 以引數的形式置於 HTTP 請求之中,而是把它放到 HTTP 頭中自己    定義的屬性裡。通過 XMLHttpRequest 這個類,能夠一次性給全部該類請求加上 csrftoken 這個 HTTP 頭屬性。並把 token 值放入當中。這樣攻克了上種方法在請求中新增 token 的不便。同一時候,通過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的位址列,也不用操心 token 會透過 Referer 洩露到其它站點中去。
 

 

 

跨站指令碼(cross site script)為了避免與樣式css混淆,所以簡稱為XSS。

XSS是一種經常出現在web應用中的電腦保安漏洞,也是web中最主流的攻擊方式。那麼什麼是XSS呢?

XSS是指惡意攻擊者利用網站沒有對使用者提交資料進行轉義處理或者過濾不足的缺點,進而新增一些程式碼,嵌入到web頁面中去。使別的使用者訪問都會執行相應的嵌入程式碼。

從而盜取使用者資料、利用使用者身份進行某種動作或者對訪問者進行病毒侵害的一種攻擊方式。

XSS攻擊的危害包括:

1、盜取各類使用者帳號,如機器登入帳號、使用者網銀帳號、各類管理員帳號

2、控制企業資料,包括讀取、篡改、新增、刪除企業敏感資料的能力

3、盜竊企業重要的具有商業價值的資料

4、非法轉賬

5、強制傳送電子郵件

6、網站掛馬

7、控制受害者機器向其它網站發起攻擊

8.盜取cookie,盜取localStorage中的內容等


2、原因解析

主要原因:過於信任客戶端提交的資料!

解決辦法:不信任任何客戶端提交的資料,只要是客戶端提交的資料就應該先進行相應的過濾處理然後方可進行下一步的操作。

進一步分析細節:

  客戶端提交的資料本來就是應用所需要的,但是惡意攻擊者利用網站對客戶端提交資料的信任,在資料中插入一些符號以及javascript程式碼,那麼這些資料將會成為應用程式碼中的一部分了。那麼攻擊者就可以肆無忌憚地展開攻擊啦。

  因此我們絕不可以信任任何客戶端提交的資料!!!


3、XSS攻擊分類

【瞭解即可,不必細究,XSS根源就是沒完全過濾客戶端提交的資料】

  3.1、反射型xss攻擊

  又稱為非永續性跨站點指令碼攻擊,它是最常見的型別的XSS。漏洞產生的原因是攻擊者注入的資料反映在響應中。一個典型的非永續性XSS包含一個帶XSS攻擊向量的連結(即每次攻擊需要使用者的點選)。

簡單例子

正常傳送訊息:

http://www.test.com/message.php?send=Hello,World!

接收者將會接收資訊並顯示Hello,Word

非正常傳送訊息:

http://www.test.com/message.php?send=<script>alert(‘foolish!’)</script>!

接收者接收訊息顯示的時候將會彈出警告視窗

  3.2、存貯型xss攻擊

  又稱為持久型跨站點指令碼,它一般發生在XSS攻擊向量(一般指XSS攻擊程式碼)儲存在網站資料庫,當一個頁面被使用者開啟的時候執行。每當使用者開啟瀏覽器,指令碼執行。持久的XSS相比非永續性XSS攻擊危害性更大,因為每當使用者開啟頁面,檢視內容時指令碼將自動執行。谷歌的orkut曾經就遭受到XSS。

簡單例子:

從名字就可瞭解到儲存型XSS攻擊就是將攻擊程式碼存入資料庫中,然後客戶端開啟時就執行這些攻擊程式碼。例如留言板

留言板表單中的表單域:<input type=“text” name=“content” value=“這裡是使用者填寫的資料”>

正常操作:

使用者是提交相應留言資訊;將資料儲存到資料庫;其他使用者訪問留言板,應用去資料並顯示。

非正常操作:

攻擊者在value填寫<script>alert(‘foolish!’)</script>【或者html其他標籤(破壞樣式。。。)、一段攻擊型程式碼】;

將資料儲存到資料庫中;

其他使用者取出資料顯示的時候,將會執行這些攻擊性程式碼


  3.3、DOMBasedXSS(基於dom的跨站點指令碼攻擊)

  基於DOM的XSS有時也稱為type0XSS。當用戶能夠通過互動修改瀏覽器頁面中的DOM(DocumentObjectModel)並顯示在瀏覽器上時,就有可能產生這種漏洞,從效果上來說它也是反射型XSS。

  通過修改頁面的DOM節點形成的XSS,稱之為DOMBasedXSS。

  前提是易受攻擊的網站有一個HTML頁面採用不安全的方式從document.location 或document.URL 或 document.referrer獲取資料(或者任何其他攻擊者可以修改的物件)。

 

從上面XSS例項以及之前文章的介紹我們知道XSS漏洞的起因就是沒有對使用者提交的資料進行嚴格的過濾處理。因此在思考解決XSS漏洞的時候,我們應該重點把握如何才能更好的將使用者提交的資料進行安全過濾。

 

現在我們公司的機制就是一個token,使用者登陸之後返回一個token,前端存放在localStorage中,每次訪問的時候可以在請求頭中的Authorization中攜帶token,這樣可以避免csrf攻擊,但是如果xss攻擊可以拿到localStorage的token。其實還是很危險的