クロスサイトリクエストフォージェリ脆弱性の解析と防御策

概要

以下のリソースを参考にしました:https://www.freebuf.com/articles/web/118352.html

CSRFとは何か

CSRF(Cross-Site Request Forgery)は日本語で「クロスサイトリクエストフォージェリ」と呼ばれ、XSSと混同されやすいですが、重要な違いがあります。CSRFではCookieを盗むのではなく、既存の認証情報を悪用します。つまり、攻撃者が被害者の身分を装い、本人が気づかぬうちにパスワード変更、管理者追加、送金などの危険な操作を行うことで、重大な被害をもたらします。

脆弱性の実演

DVWA(Damn Vulnerable Web Application)を使用して、実際の攻撃手法を検証します。DVWAの環境構築に興味がある方は、関連資料を参照してください。

DVWAを開きCSRFセクションを選択し、まずはLowレベルから開始します。ソースコードを確認すると:

<?php

if( isset( $_POST[ 'submit' ] ) ) {
    // パラメータ取得
    $new_password  = $_POST[ 'new_pass' ];
    $confirm_password = $_POST[ 'confirm_pass' ];

    // 確認処理
    if( $new_password === $confirm_password ) {
        $hashed_value = ((isset($connection) && is_object($connection)) ? mysqli_real_escape_string($connection,  $new_password ) : ((trigger_error("[MySQLConverterToo] mysql_escape_string()の呼び出しを修正してください!このコードは動作しません。", E_USER_ERROR)) ? "" : ""));
        $hashed_value = md5( $hashed_value );

        // DB更新処理
        $query = "UPDATE `users` SET password = '$hashed_value' WHERE username = '" . getCurrentUser() . "';";
        $execution = mysqli_query($connection,  $query ) or die( '' . ((is_object($connection)) ? mysqli_error($connection) : (($error_result = mysqli_connect_error()) ? $error_result : false)) . '' );

        // 結果表示
        echo "パスワードが変更されました";
    }
    else {
        // 不一致時のメッセージ
        echo "パスワードが一致しませんでした";
    }

    ((is_null($close_result = mysqli_close($connection))) ? false : $close_result);
}

?> 

コードを見ると、new_passおよびconfirm_passパラメータに対して一切の保護措置が施されていないことが分かります。これにより、攻撃者はシステム構造を把握している場合、容易に悪意のあるリンクを作成できます。ユーザーがそのリンクをクリックすると、即座にCSRF攻撃が発動します。DVWAのパスワード変更リンク例:http://example.com/DVWA/vulnerabilities/csrf/?new_pass=test1234&confirm_pass=test1234&submit=Submit

認証状態で同一ブラウザでこのリンクをクリックすると、パスワードがtest1234に変更されてしまいます。しかし、このような明確なURLは誰もクリックしないため、Burp Suiteを使ってより巧妙に構築する必要があります。パスワード変更ページで通信をキャプチャし、「Generate CSRF PoC」を選択すると、簡易的なHTMLページが生成されます。

ただし、この方法でも問題があります。クリック後すぐにパスワード変更ページに遷移するため、被害者は異常に気づいてしまいます。前述の記事のアイデアに基づき、imgタグのsrc属性を隠蔽し、誤ったURLであると誤解させるエラーページを構築することで、被害者はCSRF攻撃が進行していることに気づかないままです。以下のようなコード構成になります:

<img src="http://example.com/DVWA/vulnerabilities/csrf/?new_pass=test1234&confirm_pass=test1234&submit=Submit" border="0" style="display:none;"/>

<h1>404 Not Found</h1>
<h2>リクエストされたファイルが見つかりません</h2>

MediumレベルのDVWAソースコードでは、HTTP_REFERERヘッダ(リクエスト元URL)がSERVER_NAME(ホスト名)を含むかどうかを検証しています。つまり、同一ドメイン外からのリクエストは拒否されます。

この防御を回避するには、作成したHTMLファイル名を被害者のドメイン名に合わせるだけです。例えば、www.example.com.htmlという名前にすれば、参照元チェックを通過できます。

防御対策

1)Refererフィールドの検証

HTTPヘッダにはRefererフィールドがあり、リクエストの発信元を示します。機密データへのアクセス処理では、通常Refererフィールドとリクエスト先が同一ドメインであることを確認します。しかし、前述のようにこの方法は完全ではありません。

2)トークン検証の追加(参考:Wikipedia)

CSRFの本質は、攻撃者がユーザーを自分の準備したページに誘導することにあるため、機密情報へのアクセス時に、Cookieに保存されておらず、攻撃者が偽造できない検証データを要求すれば、攻撃を防げます。これは通常フォーム内の隠しフィールドとして実装されます。サーバーがランダムな値を生成しフォームに埋め込み、クライアントがフォーム送信時に一緒に送り返します。通常のアクセスではブラウザが正しい値を取得・送信できますが、CSRFによる偽装攻撃では攻撃者が事前に値を知ることができないため、サーバーは検証失敗としてリクエストを拒否します。

3)現在のパスワード入力要求の実装

この方式では、攻撃者が現在のパスワードを知らない限り、CSRF攻撃を実行できません。

タグ: csrf web-security Vulnerability dvwa security-token

6月13日 17:52 投稿