安全性測試入門 (三):CSRF 跨站請求僞造攻擊和防護

本篇繼續對於安全性測試話題,結合DVWA進行研習。php

CSRF(Cross-site request forgery):跨站請求僞造html

1. 跨站請求僞造攻擊

CSRF則經過假裝成受信任用戶的請求來利用受信任的網站,誘使用戶使用攻擊性網站,從而達到直接劫持用戶會話的目的。mysql

因爲如今的主流瀏覽器好比火狐和谷歌,都傾向於使用單個進程來管理用戶會話(好比咱們在FF和Chrome中,當要訪問一個新頁面時,一般是經過新增瀏覽器頁面來達到的,而不是新開一個瀏覽器客戶端進程),因此攻擊者就能夠經過用戶新開的頁面來劫持用戶的已有cookie等關鍵信息。
常見的攻擊形式,是經過郵件,QQ等即時聊天工具,給被攻擊對象發送僞造連接。被攻擊者一旦訪問了該惡意連接,攻擊即生效。sql

DVWA的相應模塊中,使用一個密碼修改功能來展現了CSRF攻擊的可能性。瀏覽器

構造攻擊

咱們觀察上述密碼修改功能所觸發的請求:安全

能夠看到這個請求很是之簡單,所需傳遞的只有三個參數服務器

  • password_new
  • password_conf
  • change

那麼若是攻擊者直接構造這樣一條請求交給被攻擊者去執行會怎麼樣?
好比我構造這樣一條URL:cookie

若是被攻擊者傻呵呵的點擊了,那麼恭喜他,他的密碼就已經被我改爲"attackerpw"了。
固然了,這個連接的攻擊意圖過於明顯了,攻擊者還能夠經過假裝一下這個連接,從而達到神不知鬼不覺的目的。session

  • 好比經過縮短連接服務:

  • 好比經過構建一個帶有攻擊代碼的頁面,誘使被攻擊者訪問:

上圖看起來就是個不明因此的網頁?但實際上訪問到網頁的時候紅框部分的攻擊代碼就已經生效了!工具

2.CSRF的防護

下面咱們看一看DVWA是如何防護跨站腳本僞造的:
Medium級別防護

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // Get input
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];

        // Do the passwords match?
        if( $pass_new == $pass_conf ) {
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );

            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

            // Feedback for the user
            $html .= "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with passwords matching
            $html .= "<pre>Passwords did not match.</pre>";
        }
    }
    else {
        // Didn't come from a trusted source
        $html .= "<pre>That request didn't look correct.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

能夠看到中級防護機制,關鍵在於如下部分:

即判斷請求來源,若是相似修改密碼的這種請求來自於未知第三方地址,那麼則不執行修改邏輯。
這是不難繞過的,只需在攻擊頁面中加入HTTP_REFERER並使其與被攻擊server一致便可。

High級別防護

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

        // Feedback for the user
        $html .= "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        $html .= "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?>

嘞了嘞了,耳熟能詳的Token他來了:

用戶每次訪問頁面,服務器會隨機生成一個Token,至關於用戶的身份牌。只有身份牌驗證經過,功能邏輯才執行。
Token是如今很流行的令牌機制,可是他也是一種比較簡單的機制,絕非無懈可擊。接口測試作的多的話應該能感覺到,咱們接口測試中常常會對Token作傳遞處理。
實際token就在網頁元素裏面,以下圖所示

咱們經過抓包、爬蟲、元素定位等方式徹底能夠獲取到,傳遞到攻擊頁面中 - 固然這會須要必定的代碼編寫量了!

Impossible級別

DVWA提供的最高級別防護機制,說穿了很是簡單,即修改密碼前,強制要求用戶輸入舊密碼。
若是不知道舊密碼,則不管怎樣也沒法修改用戶密碼。

3. CSRF防護能力測試

結合着上述討論,一樣咱們能夠總結一下這一安全測試點的測試思路。

對於CSRF跨站腳本僞造攻擊咱們能夠作:

  • 滲透性測試: 扮演攻擊者的角色,利用已知的攻擊手段嘗試跨站腳本僞造,好比本身構造請求和簡單的頁面進行攻擊。

  • 運行時測試: 實際就是功能測試,咱們能夠經過驗證系統是否存在相應的防護功能:好比token機制,請求來源驗證等。

  • 代碼審計: 瞭解了CSRF的幾個級別的防護機制,那麼就能夠經過代碼審計的方式來肯定被測應用的後臺邏輯有無相應防護機制。

還有一個問題在於,什麼樣的系統功能點多是CSRF攻擊的敏感區域呢?

從本文的例子中咱們能夠看到,當系統以一種簡單的請求方式實現某種功能時,CSRF就存在劫持用戶會話的可能性。那麼這就要求測試人員可以敏銳的發現相似的系統特性區域,而且予以判斷,是否有可能被會話劫持。

好比在一個購物平臺中,訂單的提交流程若是過於簡單,一個簡單的get請求就能實現下單功能(從這一點來講,get請求就不該用於處理敏感操做,發現這種狀況就是你測試的點!),那麼你就能夠摩拳擦掌,考慮來一次滲透測試了。

從這個角度來講,對於安全性測試,知識和技術的累積是一方面,而敏銳的思惟能力特別是逆向思惟能力更加劇要!

相關文章
相關標籤/搜索