1. 程式人生 > >ASP.NET Core 中的Ajax全域性Antiforgery Token配置

ASP.NET Core 中的Ajax全域性Antiforgery Token配置

前言

本文基於官方文件 《在 ASP.NET Core 防止跨站點請求偽造 (XSRF/CSRF) 攻擊》擴充套件另一種全域性配置Antiforgery方法,適用於使用ASP.NET Core Razor + JQuery Ajax的專案,喜歡玩前後端分離的同學可以酌情參考,但希望不要對XSRF/CSRF掉以輕心,更不要不做處理。

Antiforgery Token 介紹

跨站點請求偽造(XSRF/CSRF)攻擊跟瀏覽器中登入驗證之後儲存的Cookie有關,惡意站點通過向攻擊目標站點發起非法請求時,瀏覽器按規則是會帶上Cookie資訊的,此時被攻擊站點就會認為是使用者操作行為,如果被利用在修改密碼等操作上,對使用者的資訊保安就會帶來威脅。為抵禦 CSRF 攻擊最常用的方法是使用同步器標記模式(STP)。 而Antiforgery Token(防偽令牌)是ASP.NET Core中的STP實現方案。

STP的防禦過程:

  1. 伺服器傳送到客戶端的當前使用者的標識相關聯的令牌。
  2. 客戶端返回將令牌傳送到伺服器進行驗證。
  3. 如果伺服器收到與經過身份驗證的使用者的標識不匹配的令牌,將拒絕請求。

熟悉ASP.NET和ASP.NET Core的同學應該都不陌生,因為在ASP.NET時期就有防止XSRF攻擊的方法,ASP.NET MVC中,IHtmlHelper.BeginForm預設情況下生成防偽令牌,而ASP.NET Core中,使用FormTagHelper預設也會生成防偽令牌的。

解決方案

Form表單提交

TagHelper用法:

<form asp-controller="Manage" asp-action="ChangePassword" method="post">
    ...
</form>

HtmlHelper 生成Form的用法:

@using (Html.BeginForm("ChangePassword", "Manage"))
{
    ...
}

普通html form表單用法:

<form action="/" method="post">
    @Html.AntiForgeryToken()
</form>

那麼在Razor渲染之後,表單中就會生成一個隱藏的表單欄位:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

那麼Ajax中要怎麼處理呢?

官方文件雖然有提到Ajax的處理方法,但是它指的Ajax是js原生實現XMLHttpRequest,而不是我們一般所認識的JQuery.ajax。所以本文就要介紹一下在使用JQuery.ajax時的全域性配置。

場景一、從普通表單獲取Antiforgery Token

這種方法跟上面提到的Form表單提交一致,只要把所生成的隱藏的表單欄位也一併提交到伺服器即可。


$.ajax({
    url:"/Manage/ChangePassword",
    type:"post"
    data: { "__RequestVerificationToken":"CfDJ8NrAkS ... s2-m9Yw" }
})

但是這種方法有個弊端,就是需要配置的東西很多,又要在Contorller中加[ValidateAntiForgeryToken]特性,又要在表單中處理使其生成隱藏欄位。

有沒有更方便的方法?當然有!而且即使是文件中號稱自動防範 XSRF/CSRF的Razor Pages都同樣需要!因為它並沒有處理Ajax的場景。

場景二、全域性配置,自動處理

全域性獲取Forgery Token

全域性(每個頁面)獲取Forgery Token就是文件中提到的注入Microsoft.AspNetCore.Antiforgery.IAntiforgery並呼叫GetAndStoreTokens方法,但是由於需要達到全域性獲取,我需要把這個方法的呼叫寫到佈局頁,如預設MVC模版的Views/Shared/_Layout.cshtml

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

<script>
    var csrfToken = '@GetAntiXsrfRequestToken()';
</script>

Ajax全域性配置

JQuery.ajax裡全域性設定頭部的方法是$.ajaxSetup,按照文件,把所需的頭部欄位RequestVerificationToken配置上上面獲取到的令牌變數csrfToken,即可實現在每個Ajax請求都帶有Forgery Token。

(function (window, document, $) {
    $.ajaxSetup({
        headers: {
            'RequestVerificationToken': csrfToken
        }
    });
})(window, document, jQuery);

總結

雖然現在流行前後端分離了,包括我在內,也用上高大上的React、Angular、Vue等優秀框架,Github前端也把JQuery去掉了,但是Razor在ASP.NET Core中的份量有增無減,2.0版本帶來了更輕量的Razor Pages, 因此Razor+JQuery的熱度不會那麼快退去,希望這篇文章能給大家在Razor+JQuery技術的使用過程中帶來一點參考價值。