本篇目錄
介紹###
CSRF【Cross-Site Request Forgery】跨站請求偽造是一種攻擊類型,一般指的是一個惡意的網站、郵件、博客、即時消息、或程序使得用戶的web瀏覽器對當前用戶已認證的可信任網站執行一個自己不願執行的操作。想要詳細了解的可以查看百度CSRF,擴展閱讀OWASP。
這里簡明描述一下如何在ASP.NET Web API中實現。
ABP框架盡可能地簡化並 自動化了CSRF保護,現成的啟動模板已經做了預配置。本文,會解釋如何將它集成到ASP.NET平台的,以及它是如何工作的。
HTTP動詞
無需對GET,HEAD,OPTIONS,TRACEHTTP動詞做保護操作,因為正常情況下它們應該是無副作用的(不會更改數據庫)。ABP只對POST,PUT,PATCH,DELETE動詞實現了反偽造(Anti-Forgery)保護,可以使用本文中定義的特性來更改該行為。
ASP.NET MVC###
功能
大家都知道,ASP.NET MVC有自己內置的反偽造系統,但它有一些不足:
- 需要為保護的所有actions添加ValidateAntiForgeryToken特性,這個容易忘記。
- ValidateAntiForgeryToken特性只檢查HTML 表單域中的__RequestVerificationToken,這就使得在AJAX請求中使用它非常困難或不可能,尤其是以"application/json"作為content-type發送請求時。在Ajax請求中,通常會在請求頭中設置token。
- 在JS代碼中很難訪問驗證token,尤其是不在.cshtml文件中寫JS。但我們需要在AJax請求中訪問使用。
- 即使可以在js中訪問token,也需要為每個請求都在頭部手動加入,很是麻煩。
ABP做了下面這些事情來客服上面的困難:
- actions會被自動保護(通過AbpAntiForgeryMvcFilter)。自動保護可以應對大多數情況。當然,可以使用DisableAbpAntiForgeryTokenValidation特性為任何action和Controller關閉自動保護,也可以使用 ValidateAbpAntiForgeryToken特性打開。
- 除了HTML的表單域,AbpAntiForgeryMvcFilter也會檢查請求頭中的token。因此,可以很容易對ajax請求使用反偽造token保護。
- 在js中可以使用abp.security.antiForgery.getToken()函數獲得token。
- 為所有的ajax請求頭部自動添加反偽造token。
集成
啟動模板已經集成了現成的CSRF保護,如果需要手動將它添加到你的項目,那么請參照以下步驟。
Layout 視圖
在Layout視圖中添加以下代碼:
@{
SetAntiForgeryCookie();
}
這樣,所有使用了這個布局頁的頁面都會包含這句代碼了,該方法定義在ABP視圖基類中,它會創建和設置正確的token cookie,使得在js端可以工作。如果有多個Layout的話,需要為每個布局添加上面的代碼。
對於ASP.NET MVC 應用,只需要做這么多,所有的ajax請求都會自動工作。但是對於HTML 表單仍然需要使用** @Html.AntiForgeryToken()** HTML幫助方法,因為表單不是通過Ajax提交的,但是不需要在相應的action上使用ValidateAbpAntiForgeryToken 特性了。
配置
XSRF默認是打開的,也可以在模塊的PreInitialize方法中關閉或配置,如下:
Configuration.Modules.AbpWeb().AntiForgery.IsEnabled = false;
也可以使用Configuration.Modules.AbpWebCommon().AntiForgery對象配置token和cookie名稱。
ASP.NET WEB API###
功能
ASP.NET Web API不包括反偽造機制,ABP為ASP.NET Web API Controllers提供了基礎設施來添加CSRF保護,並且是完全自動化的。
集成
ASP.NET MVC客戶端
如果在MVC項目中使用了Web API,那么不需要額外的配置。只要Ajax請求是從一個配置的MVC應用中發出的,即使你的Web API層自宿主在其它進程中,也不需要配置。
其它客戶端
如果你的客戶端是其它類型的應用(比如,一個獨立的angularjs應用,它不能像之前描述的那樣使用SetAntiForgeryCookie()方法),那么你應該提供一種設置反偽造token cookie的方法。一種可能的實現方式是像下面那樣創建一個api控制器:
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了。
ASP.NET Core###【以后補上】
客戶端類庫###
jQuery
abp.jquery.js中定義了一個ajax攔截器,它可以將反偽造請求token添加到每個請求的請求頭中,它會從abp.security.antiForgery.getToken()函數中獲得token。
Angularjs
Angularjs會將反偽造token自動添加到所有的ajax請求中,請點擊鏈接查看Angularjs的XSRF保護一節。ABP默認使用了相同的cookie和header名稱。因此,Angularjs集成是現成可用的。
其它類庫
如果你使用了其它類庫做Ajax請求,那么有三種選擇:
Intercept XMLHttpRequest
因為所有的類庫都使用了原生的js 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),因此,請查看文檔學習如何攔截請求以及操作頭部。
Add the Header Manually
最后,可以使用abp.security.antiForgery.getToken()獲取token,然后手動為每個請求添加請求頭,但是很可能不需要這么做,而是按照上面的方法解決問題。
內部原理###
你可能想知道ABP是如何處理這個的,實際上,ABP使用了和之前文檔描述的angularjs機制是一樣的。ABP會將token保存到一個cookie中,然后使用那個cookie設置請求頭。這個實現也很好地集成到了ASP.NET MVC, Web API 和 Core框架。