前言
本文基於官方文檔 《在 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技術的使用過程中帶來一點參考價值。