ABP官方文件(四十二)【CSRF和XSRF保護】
6.9 CSRF和XSRF保護
6.9.1 簡介
Cross-Site Request Forgery (CSRF) 跨站請求偽造是一種攻擊,發生在具有惡意的網站,email,blog,即時訊息,或者程式導致使用者的web瀏覽器在一個受信用的網站去執行了某個有害的行為來獲取當前使用者的認證資訊,詳細瞭解請點選這裡腦補。
ABP框架儘可能的簡化且自動化CSRF保護。啟動模板
實現了開箱即用的預配置。在這篇文件中,我們會展示它是如何整合到ASP.NET,以及它是如何工作的。
Http 謂詞
對於 HTTP謂詞是 GET,HEAD,OPTIONS以及TRACE 的Action,我們不需要進行CSRF保護,因為它們是無副作用的操作(不會更改資料庫)。ABP假定(ABP僅對這些謂詞實現了反偽造保護,如:POST,PUT,PATH以及DELETE
)你能夠使用一些已定義的特性改變這些行為(應該是說將 [POST] 等特性加裝在以Get等開頭的方法上)。
6.9.2 ASP.NET MVC
Features
正如你所瞭解到的ASP.NET MVC有自己內建的AntiForgery功能,但是它具有以下不完美的地方:
需要對所有的Actions新增 ValidateAntiForgeryToken 才能實現保護。我們可能會忘記新增它到需要執行保護的Action上。
ValidateAntiForgeryToken 特性僅檢查HTML表單中的 __RequestVerificationToken 欄位。這在 AJAX 請求中使用它是很難且不可能的,特別是在你傳送的content-type是 application/json
在AJAX請求中我們需要取得token並且使用它,但是在指令碼程式碼中很難取得verification token(特別是你沒有在.cshtml檔案中寫指令碼)。
即使我們能夠在指令碼中得到token,我們應該手動的新增token到每個請求頭中。
ABP做了以下一些事情克服了這些困難:
不在需要對這些Action 如:POST,PUT,PATH以及DELETE 新增 ValidateAntiForgeryToken 特性,因為它們會自動的保護起來(通過 AbpAntiForgeryMvcFilter
在指令碼中提供了 abp.security.antiForgery.getToken() 函式來取得token,即使你不需要它。
對所有的AJAX請求自動的新增 anti forgery token 到請求頭中。
因此,相對於ASP.NET MVC 自帶AntiForgery功能,它的幾乎是無縫的工作。
整合
開始模板已經對CSRF進行了開箱即用的整合。如果你需要手動新增它到你的專案(你的專案先於我新增該項功能的時候就已經建立),請跟隨下面指南:
Layout View
我們應該新增下面程式碼到我們的佈局檢視:
@{
SetAntiForgeryCookie();
}
因此,所有使用了該檢視的頁面都會包含它。這個方法被定義在ABP檢視的基類中。它會建立且設定token到cookie中,並且能在客戶端指令碼執行。如果你有多個佈局檢視,請把該程式碼新增到所有的佈局檢視中。
這就是我們應該對ASP.NET應用所要做的。所有的AJAX請求會自動的工作。但是我們應該在那些不需要通過AJAX來提交POSt請求的表單中使用 @Html.AntiForgeryToken() 方法(並且對相信的Action我們不需要新增 ValidateAbpAntiForgeryToken 特性)。
Configuration
XSRF保護預設是開啟的。你可以在模組的 Preinitialize 方法中禁用。如:
Configuration.Modules.AbpWeb().AntiForgery.IsEnabled = false;
你也可以使用 Configuration.Modules.AbpWebCommon().AntiForgery 來配置token和cookie的名稱。
注意:如果使用了偽造驗證,如果使用Swagger Ui來除錯動態WebApi,請參考 Swagger UI整合的文件。
6.9.3 ASP.NET Web API
Features
ASP.NET Web API 沒有提供防偽造這樣的機制。當時ABP對ASP.NET Web API提供了CSRF保護的基礎設施並且自動完成這個功能。
整合
與 ASP.NET MVC Clients 整合
如果你在MVC專案中使用Web API,不需要任何額外的配置。即使你的Web API層是self-hosting在另外的程序中。不需要任何配置,只需配置好來自MVC應用的AJAX請求。
與其他Clients整合
如果你的客戶端是不同種類的應用(沒有如前面所述:在一個獨立的angularjs中使用 SetAntiForgeryCookie() 方法)。那麼你應該提供一個設定反偽造token的cookie。一個可能的方式是像下面一樣建立一個Api Controller:
using System.Net.Http;
using Abp.Web.Security.AntiForgery;
using Abp.WebApi.Controllers;
namespace AngularForgeryDemo.Controllers
{
public class AntiForgeryController : AbpApiController
{
private readonly IAbpAntiForgeryManager _antiForgeryManager;
public AntiForgeryController(IAbpAntiForgeryManager antiForgeryManager)
{
_antiForgeryManager = antiForgeryManager;
}
public HttpResponseMessage GetTokenCookie()
{
var response = new HttpResponseMessage();
_antiForgeryManager.SetCookie(response.Headers);
return response;
}
}
}
那麼你可以從客戶端呼叫該action來設定cookie。
6.9.3 ASP.NET Core
Features
與之前的版本(ASP.NET MVC 5.x)相比,ASP.NET Core MVC 有一個很好的反偽造機制:
它有個 AutoValidateAntiforgeryTokenAttribute 類會自動的對所有的 POST,PUT,PATH以及DELETE Action自動實施反偽造驗證。
它有 ValidateAntiForgeryToken和IgnoreAntiforgeryToken 特性來控制toekn驗證。
如果你沒有禁用反偽造功能,它會自動的新增反偽造安全token在html表單中。所以在大多數情況下你不需要呼叫 @Html.AntiForgeryToken()。
他可以從HTTP頭或者Form表單的欄位中讀取請求的token。
ABP 添加了以下功能:
自動的為所有的AJXA請求添加了反偽造token。
在指令碼中提供了 abp.security.antiForgery.getToken() 來取得token,即使你不使用它。
整合
開始模板已經對CSRF進行了開箱即用的整合。如果你需要手動新增它到你的專案(你的專案先於我新增該項功能的時候就已經建立),請跟隨下面指南:
Startup Class
首先,當我們在MVC啟動類中配置ConfigureServices時,我們應該新增 AutoValidateAntiforgeryTokenAttribute 特性到全域性過濾器中。
services.AddMvc(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
因此,所有的MVC Actions將會對反偽造token進行自動驗證(除了之前所描述的 GET,HEAD,OPTIONS以及TRACE 外)。
Layout View
我們應該在佈局檢視中新增下面的程式碼:
@using Abp.Web.Security.AntiForgery
@inject IAbpAntiForgeryManager AbpAntiForgeryManager
@{
AbpAntiForgeryManager.SetCookie(Context);
}
因此,所有使用了該檢視的頁面都會包含它。這個方法被定義在ABP檢視的基類中。它會建立且設定token到cookie中,並且能在客戶端指令碼執行。如果你有多個佈局檢視,請把該程式碼新增到所有的佈局檢視中。
這就是我們應該為ASP.NET Core MVC應用所要做的。所有的AJAX請求會自動的工作。對於非AJAX表單提交,如果你使用在你的表單中使用了asp-* 的標籤,ASP.NET Core會自動新增反偽造token欄位。所以正常情況下你不需要呼叫 @Html.AntiForgeryToken()。
6.9.4 客戶端庫
在所有的AJAX請求頭中反偽造token應該被提供,正如我們前面所描述的。在這裡我們將會看到具體實現。
JQuery
abp.jquery.js 定義了AJAX攔截器,這可以對每個AJAX請求新增反偽造token到請求頭中。使用 abp.security.antiForgery.getToken() 方法來取得token。
AngularJs
AngularJs會自動的新增反偽造token到所有的AJAX請求中,詳細請查閱Angualrjs的跨站請求偽造保護。ABP預設使用相同的cookie和頭名稱。所以AngularJs集成了開箱即用的功能。
其他庫
如果你使用了其他的指令碼庫來實現AJAX請求,你有三個選擇可以做:
Intercept XMLHttpRequest
因為所有的庫都會使用指令碼的原生AJAX物件:XMLHttpRequest 你可以像下面一樣定義一個簡單的攔截器將token新增到請求頭中:
(function (send) {
XMLHttpRequest.prototype.send = function (data) {
this.setRequestHeader(abp.security.antiForgery.tokenHeaderName, abp.security.antiForgery.getToken());
return send.call(this, data);
};
})(XMLHttpRequest.prototype.send);
Use Library Interceptor
一個好使用的庫會提供攔截點給你如JQuery和angularjs。所以,你應該學習這些庫的文件來了解如何攔截請求並操作請求頭。
手動新增請求頭
最後一種選擇,你可以使用 abp.security.antiForgery.getToken() 方法取得token並且手動的新增它到每個AJAX請求中。但是你可能不需要這要做,你可以按照上面所述來解決問題。
Internals
你可能想知道ABP是如何處理它的。事實上,在前面提到的angularjs文件中,我們使用了相同的機制來描述。ABP儲存token到cookie(如前所述),並且使用該cookie來設定請求頭。為了驗證防偽造token,它也很好的整合到了ASP.NET,Web API和Core框架。