ASP.NET MVCにおけるAjax通信のCSRF対策

ASP.NET

SPA で非同期通信を多用すると思います。その際に、非同期通信の場合の CSRF 対策について調査ました。

スポンサーリンク

通常の同期処理(ページ遷移)の場合

ASP.NET MVC では CSRF 対策が超簡単です。
ViewのForm の中で Razor の @Html.AntiForgeryToken() を呼ぶだけでトークンを埋め込むことが出来ます。
トークンを検証するには Controller で ActionMethod の属性に ValidationAntiForgeryToken を指定するだけです。

@using (Html.BeginForm()){
    @Html.AntiForgeryToken()
    // 略
}
[ValidationAntiForgeryToken]
[HttpPost]
public ActionResult Create(ViewModel model){
    // 略
}

ところが、非同期処理(Ajax)の場合は少々工夫が必要になります。

非同期処理(Ajax)の場合

Razor でクッキーのトークンとフォームのトークンを発行する関数を作成します。
作成した関数を呼び、hidden 値に設定し、POST 時にヘッダに付加してリクエストを送信します。

<script>
    @functions{
        public string GenerateRequestVerificationToken()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;
        }
    }
</script>

<input type="hidden" id="requestValificationToken" value="@GenerateRequestValificationToken()" />
$.ajax({
    url: "http://test/Create",
    type: "POST",
    dataType: "json",
    data: {
        data: hoge
    },
    headers: {
        "RequestVerificationToken": $("#requestVerificationToken").val()
    }
});

ヘッダに付与されたトークンを検証する関数を用意します。

private void ValidateAntiForgeryToken()
{
    string cookieToken = "";
    string formToken = "";
    var tokenHeader = Request.Headers["RequestVerificationToken"];
    if (!String.IsNullOrEmpty(tokenHeader))
    {
        string[] tokens = tokenHeader.Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}

Controller の ActionMethod で先ほどの関数を呼びます。

public ActionResult Create(){
    // 自前でヘッダに付与されたトークンを検証する
    ValidateAntiForgeryToken();
    // 略
}
タイトルとURLをコピーしました