日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

初探CSRF在ASP.NET Core中的处理方式

發(fā)布時間:2023/12/4 asp.net 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初探CSRF在ASP.NET Core中的处理方式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

前幾天,有個朋友問我關(guān)于AntiForgeryToken問題,由于對這一塊的理解也并不深入,所以就去研究了一番,梳理了一下。

在梳理之前,還需要簡單了解一下背景知識。

AntiForgeryToken?可以說是處理/預(yù)防CSRF的一種處理方案。

那么什么是CSRF呢?

CSRF(Cross-site request forgery)是跨站請求偽造,也被稱為One Click Attack或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網(wǎng)站的惡意利用。

簡單理解的話就是:有人盜用了你的身份,并且用你的名義發(fā)送惡意請求

最近幾年,CSRF處于不溫不火的地位,但是還是要對這個小心防范!

更加詳細(xì)的內(nèi)容可以參考維基百科:Cross-site request forgery

下面從使用的角度來分析一下CSRF在 ASP.NET Core中的處理,個人認(rèn)為主要有下面兩大塊

  • 視圖層面

  • 控制器層面

視圖層面

用法

@Html.AntiForgeryToken()

在視圖層面的用法相對比較簡單,用的還是HtmlHelper的那一套東西。在Form表單中加上這一句就可以了。

原理淺析

當(dāng)在表單中添加了上面的代碼后,頁面會生成一個隱藏域,隱藏域的值是一個生成的token(防偽標(biāo)識),類似下面的例子

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8FBn4LzSYglJpE6Q0fWvZ8WDMTgwK49lDU1XGuP5-5j4JlSCML_IDOO3XDL5EOyI_mS2Ux7lLSfI7ASQnIIxo2ScEJvnABf9v51TUZl_iM2S63zuiPK4lcXRPa_KUUDbK-LS4HD16pJusFRppj-dEGc" />

其中的name="__RequestVerificationToken"是定義的一個const變量,value=XXXXX是根據(jù)一堆東西進(jìn)行base64編碼,并對base64編碼后的內(nèi)容進(jìn)行簡單處理的結(jié)果,具體的實(shí)現(xiàn)可以參見Base64UrlTextEncoder.cs

生成上面隱藏域的代碼在AntiforgeryExtensions這個文件里面,github上的源碼文件:AntiforgeryExtensions.cs

其中重點(diǎn)的方法如下:

public void WriteTo(TextWriter writer, HtmlEncoder encoder){writer.Write("<input name=\"");encoder.Encode(writer, _fieldName);writer.Write("\" type=\"hidden\" value=\"");encoder.Encode(writer, _requestToken);writer.Write("\" />"); }

相當(dāng)?shù)那逦髁?#xff01;

控制器層面

用法

[ValidateAntiForgeryToken] [AutoValidateAntiforgeryToken] [IgnoreAntiforgeryToken]

這三個都是可以基于類或方法的,所以我們只要在某個控制器或者是在某個Action上面加上這些Attribute就可以了。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]

原理淺析

本質(zhì)是Filter(過濾器),驗(yàn)證上面隱藏域的value

過濾器實(shí)現(xiàn):ValidateAntiforgeryTokenAuthorizationFilter和AutoValidateAntiforgeryTokenAuthorizationFilter

其中 AutoValidateAntiforgeryTokenAuthorizationFilter是繼承了ValidateAntiforgeryTokenAuthorizationFilter,只重寫了其中的ShouldValidate方法。

下面貼出ValidateAntiforgeryTokenAuthorizationFilter的核心方法:

public class ValidateAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy { ? ?public async Task OnAuthorizationAsync(AuthorizationFilterContext context){ ? ? ? ?if (context == null){throw new ArgumentNullException(nameof(context));} ? ? ? ?if (IsClosestAntiforgeryPolicy(context.Filters) && ShouldValidate(context)){ ? ? ? ? ? ?try{await _antiforgery.ValidateRequestAsync(context.HttpContext);}catch (AntiforgeryValidationException exception){_logger.AntiforgeryTokenInvalid(exception.Message, exception);context.Result = new BadRequestResult();}}} }

完整實(shí)現(xiàn)可參見github源碼:ValidateAntiforgeryTokenAuthorizationFilter.cs

當(dāng)然這里的過濾器只是一個入口,相關(guān)的驗(yàn)證并不是在這里實(shí)現(xiàn)的。而是在Antiforgery這個項(xiàng)目上,其實(shí)說這個模塊可能會更貼切一些。

由于是面向接口的編程,所以要知道具體的實(shí)現(xiàn),就要找到對應(yīng)的實(shí)現(xiàn)類才可以。

Antiforgery這個項(xiàng)目中,有這樣一個擴(kuò)展方法AntiforgeryServiceCollectionExtensions,里面告訴了我們相對應(yīng)的實(shí)現(xiàn)是DefaultAntiforgery這個類。其實(shí)Nancy的源碼看多了,看一下類的命名就應(yīng)該能知道個八九不離十。

?services.TryAddSingleton<IAntiforgery, DefaultAntiforgery>();

其中還涉及到了IServiceCollection,但這不是本文的重點(diǎn),所以不會展開講這個,只是提出它在 .net core中是一個重要的點(diǎn)。

好了,回歸正題!要驗(yàn)證是否是合法的請求,自然要先拿到要驗(yàn)證的內(nèi)容。

var tokens = await _tokenStore.GetRequestTokensAsync(httpContext);

它是從Cookie中拿到一個指定的前綴為.AspNetCore.Antiforgery.的Cookie,并根據(jù)這個Cookie進(jìn)行后面相應(yīng)的判斷。下面是驗(yàn)證的具體實(shí)現(xiàn):

public bool TryValidateTokenSet( ? ?HttpContext httpContext, ? ?AntiforgeryToken cookieToken, ? ?AntiforgeryToken requestToken, ? ?out string message){ ? ?//去掉了部分非空的判斷// Do the tokens have the correct format?if (!cookieToken.IsCookieToken || requestToken.IsCookieToken){message = Resources.AntiforgeryToken_TokensSwapped; ? ? ? ?return false;} ? ?// Are the security tokens embedded in each incoming token identical?if (!object.Equals(cookieToken.SecurityToken, requestToken.SecurityToken)){message = Resources.AntiforgeryToken_SecurityTokenMismatch; ? ? ? ?return false;} ? ?// Is the incoming token meant for the current user?var currentUsername = string.Empty;BinaryBlob currentClaimUid = null; ? ?var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User); ? ?if (authenticatedIdentity != null){currentClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User)); ? ? ? ?if (currentClaimUid == null){currentUsername = authenticatedIdentity.Name ?? string.Empty;}} ? ?// OpenID and other similar authentication schemes use URIs for the username.// These should be treated as case-sensitive.var comparer = StringComparer.OrdinalIgnoreCase; ? ?if (currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase)){comparer = StringComparer.Ordinal;} ? ?if (!comparer.Equals(requestToken.Username, currentUsername)){message = Resources.FormatAntiforgeryToken_UsernameMismatch(requestToken.Username, currentUsername); ? ? ? ?return false;} ? ?if (!object.Equals(requestToken.ClaimUid, currentClaimUid)){message = Resources.AntiforgeryToken_ClaimUidMismatch; ? ? ? ?return false;} ? ?// Is the AdditionalData valid?if (_additionalDataProvider != null &&!_additionalDataProvider.ValidateAdditionalData(httpContext, requestToken.AdditionalData)){message = Resources.AntiforgeryToken_AdditionalDataCheckFailed; ? ? ? ?return false;}message = null; ? ?return true; }

注:驗(yàn)證前還有一個反序列化的過程,這個反序列化就是從Cookie中拿到要判斷的cookietoken和requesttoken

如何使用

前面粗略介紹了一下其內(nèi)部的實(shí)現(xiàn),下面再用個簡單的例子來看看具體的使用情況:

使用一:常規(guī)的Form表單

先在視圖添加一個Form表單

<form id="form1" action="/home/antiform" method="post"> ? ?@Html.AntiForgeryToken() ? ?<p><input type="text" name="message" /></p> ? ?<p><input type="submit" value="Send by Form" /></p></form>

在控制器添加一個Action

[ValidateAntiForgeryToken] [HttpPost]public IActionResult AntiForm(string message){ ? ?return Content(message); }

來看看生成的html是不是如我們前面所說,將@Html.AntiForgeryToken()輸出為一個name為__RequestVerificationToken的隱藏域:

再來看看cookie的相關(guān)信息:

可以看到,一切都還是按照前面所說的執(zhí)行。在輸入框輸入信息并點(diǎn)擊按鈕也能正常顯示我們輸入的文字。

使用二:Ajax提交

表單:

<form id="form2" action="/home/antiajax" method="post"> ? ?@Html.AntiForgeryToken() ? ?<p><input type="text" name="message" id="ajaxMsg" /></p> ? ?<p><input type="button" id="btnAjax" value="Send by Ajax" /></p></form>

js:

$(function () {$("#btnAjax").on("click", function () {$("#form2").submit(); ? ? ? ? ? ? ? ?}); })

這樣子的寫法也是和上面的結(jié)果是一樣的!

怕的是出現(xiàn)下面這樣的寫法:

$.ajax({type: "post",dataType: "html",url: '@Url.Action("AntiAjax", "Home")',data: { message: $('#ajaxMsg').val() },success: function (result) {alert(result);},error: function (err, scnd) {alert(err.statusText);} });

這樣,正常情況下確實(shí)是看不出任何毛病,但是實(shí)際確是下面的結(jié)果(400錯誤):

相信大家也都發(fā)現(xiàn)了問題的所在了!!隱藏域的相關(guān)內(nèi)容并沒有一起post過去!!

處理方法有兩種:

方法一:

在data中加上隱藏域相關(guān)的內(nèi)容,大致如下:

$.ajax({ ? ?// ? ? ? ?data: { message: $('#ajaxMsg').val(), __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val()} });

方法二:

在請求中添加一個header

$("#btnAjax").on("click", function () { ? ?var token = $("input[name='__RequestVerificationToken']").val();$.ajax({type: "post",dataType: "html",url: '@Url.Action("AntiAjax", "Home")',data: { message: $('#ajaxMsg').val() },headers:{ ? ? ? ? ? ?"RequestVerificationToken": token},success: function (result) {alert(result);},error: function (err, scnd) {alert(err.statusText);}}); });

這樣就能處理上面出現(xiàn)的問題了!

使用三:自定義相關(guān)信息

可能會有不少人覺得,像那個生成的隱藏域那個name能不能換成自己的,那個cookie的名字能不能換成自己的??

答案是肯定可以的,下面簡單示范一下:

在Startup的ConfigureServices方法中,添加下面的內(nèi)容即可對默認(rèn)的名稱進(jìn)行相應(yīng)的修改。

services.AddAntiforgery(option => { ? ?option.CookieName = "CUSTOMER-CSRF-COOKIE"; ? ?option.FormFieldName = "CustomerFieldName"; ? ?option.HeaderName = "CUSTOMER-CSRF-HEADER"; });

相應(yīng)的,ajax請求也要做修改:

var token = $("input[name='CustomerFieldName']").val();//隱藏域的名稱要改$.ajax({type: "post",dataType: "html",url: '@Url.Action("AntiAjax", "Home")',data: { message: $('#ajaxMsg').val() },headers:{ ? ? ? ?"CUSTOMER-CSRF-HEADER": token //注意header要修改},success: function (result) {alert(result);},error: function (err, scnd) {alert(err.statusText);} });

下面是效果:

Form表單:

Cookie:

本文涉及到的相關(guān)項(xiàng)目:

  • Mvc

  • Antiforgery

  • HttpAbstractions

關(guān)于CSRF相關(guān)的內(nèi)容

Preventing Cross-Site Request Forgery (XSRF/CSRF) Attacks in ASP.NET Core

淺談CSRF攻擊方式

原文地址:http://www.cnblogs.com/catcher1994/p/6720212.html


.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注

總結(jié)

以上是生活随笔為你收集整理的初探CSRF在ASP.NET Core中的处理方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。