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的防禦過程:
- 伺服器傳送到客戶端的當前使用者的標識相關聯的令牌。
- 客戶端返回將令牌傳送到伺服器進行驗證。
- 如果伺服器收到與經過身份驗證的使用者的標識不匹配的令牌,將拒絕請求。
熟悉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技術的使用過程中帶來一點參考價值。