1. 程式人生 > >Web安全之CSRF跨站請求偽造攻擊

Web安全之CSRF跨站請求偽造攻擊

CSRF全稱Cross-Site Request Forgery,跨站請求偽造攻擊。
其攻擊原理是:
攻擊者在使用者瀏覽網頁時,利用頁面元素(例如img的src),強迫受害者的瀏覽器向Web應用程式傳送一個改變使用者資訊的請求。
由於發生CSRF攻擊後,攻擊者是強迫使用者向伺服器傳送請求,所以會造成使用者資訊被迫修改,更嚴重者引發蠕蟲攻擊。

CSRF攻擊可以從站外站內發起。
站內發起CSRF攻擊,需要利用網站本身的業務,比如“自定義頭像”功能,惡意使用者指定自己的頭像URL是一個修改使用者資訊的連結,當其他已登入使用者瀏覽惡意使用者頭像時,會自動向這個連結傳送修改資訊請求。
站外

傳送請求,則需要惡意使用者在自己的伺服器上,放一個自動提交修改個人資訊的htm頁面,並把頁面地址發給受害者使用者,受害者使用者開啟時,會發起一個請求。
如果惡意使用者能夠知道網站管理後臺某項功能的URL,就可以直接攻擊管理員,強迫管理員執行惡意使用者定義的操作。

攻擊

下面我們舉個例子。
一個沒有CSRF安全防禦的程式碼如下:

$userid=$_SESSION["userid"];
$email=$_REQUEST["email"];
$tel=$_REQUEST["tel"];
$realname=$_REQUEST["realname"];
$params = array();
$params
[0] =$email; $params[1] = $tel; $params[2] = $realname; $params[3] =$userid; $sql = "update user set email=?,tel=?,realname=? where userid=?"; execUpdate($sql,$params);

程式碼中接收使用者提交的引數“email,tel,realname”,之後修改了該使用者的資料,一旦接收到一個使用者發來的請求,就執行修改操作。
提交表單程式碼:

<form action="http://localhost/servlet/modify"
method="POST">
<input name="email"> <input name="tel"> <input name="realname"> <input name="userid"> <input type="submit"> </form>

當用戶點提交時,就會觸發修改操作。

下面我們說說如何攻擊這麼一個網站。如果該網站啊alibaba.com的一個部分,那麼我們可以構建兩個html頁面:
1. 第一個頁面a.html,其中通過iframe指向b.html,把寬度和高度都設為0:

<iframe src="b.htm" width="0" height="0"></frame>

這是為了當攻擊發生時,受害使用者看不到提交成功結果頁面。
2. 頁面b.html中,有一個表單和一段指令碼,指令碼的作用是,當頁面載入時自動提交這個表單:

<form id="modify" action="http://alibaba.com/servlet/modify" method="POST">
<input name="email">
<input name="tel">
<input name="realname">
<input name="userid">
<input type="submit">
</form>
<script>
  document.getElementById("modify").submit();
</script>

注意表單的指向是alibaba.com/servlet/modify
3. 將a.html放在自己的web伺服器上,傳送給登入使用者即可:
這裡寫圖片描述
4. 使用者開啟a.html後,會自動提交表單,傳送給alibaba.com下那個存在CSRF漏洞的Web應用,所以使用者的資訊,就被迫修改了。而且整個攻擊過程中,受害者僅僅看到一個空白頁面,且不知道自己資訊已被修改。

防禦

有攻擊就有防禦,要防禦CSRF工具,必須遵循以下三步:
1. 在使用者登入時,設定一個隨機的TOKEN也就是令牌,同時種植在使用者的cookie中,當用戶瀏覽器關閉、或使用者再次登入時,清除TOKEN:

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

植入令牌到cookie中。
2. 在表單中生成一個隱藏域,它的值就是cookie中隨機TOKEN:

<?php
    $hash = md5($_COOKIE['cookie']);
  ?>
  <form action="http://localhost/servlet/modify"method="POST">
      <input type=”hidden” name=”hash” value=”<?=$hash;?>”>
       <input name="email">
       <input name="tel">
       <input name="realname">
       <input name="userid">
       <input type="submit">
   </form>

通過md5加密將客戶端cookie中令牌值傳遞到伺服器端。
3. 表單被提交後,就可以判斷表單中的TOKEN和使用者cookie中的TOKEN是否一致,如果不一致或沒有這個值,就是CSRF攻擊:

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

以上就是防禦CSRF的基本方法了。那麼還有幾個問題:
1. 如果表單不是post而是get方式提交呢?
如果用get方式提交,TOKEN會出現在url中,攻擊者可以引誘攻擊者點選自己的網站,然後從http頭部中的referrer 的url來獲取TOKEN,再來攻擊。
2. 為什麼不直接驗證referrer?
網站內部也可能出現CSRF攻擊,而referrer 只能判斷是否來自可信任網站。
3. 如果先發生XSS攻擊,攻擊者可以拿到使用者頁面的TOKEN怎麼辦?
CSRF防禦是建立在XSS防禦之後的防禦,如果XSS防禦失效,攻擊者可以拿到使用者頁面所有資訊,CSRF當然會失去效果。當然我們還是可以防止這種情況的發生,就是在表單提交的時候要求輸入驗證碼。這樣就可以防禦啦。