91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在ASP.NET Core中對CSRF進行處理

發布時間:2021-01-19 17:18:31 來源:億速云 閱讀:324 作者:Leah 欄目:開發技術

怎么在ASP.NET Core中對CSRF進行處理?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

那么什么是CSRF呢?

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

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

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

更加詳細的內容可以參考維基百科:Cross-site request forgery

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

  • 視圖層面

  • 控制器

層面視圖層面

用法

@Html.AntiForgeryToken()

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

原理淺析

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

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

其中的name="__RequestVerificationToken"是定義的一個const變量,value=XXXXX是根據一堆東西進行base64編碼,并對base64編碼后的內容進行簡單處理的結果,具體的實現可以參見Base64UrlTextEncoder.cs

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

其中重點的方法如下:

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("\" />");
}

相當的清晰明了!

控制器層面

用法

[ValidateAntiForgeryToken]
[AutoValidateAntiforgeryToken]
[IgnoreAntiforgeryToken]

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

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

原理淺析

本質是Filter(過濾器),驗證上面隱藏域的value

過濾器實現: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();
 }
 }
 }
}

完整實現可參見github源碼:ValidateAntiforgeryTokenAuthorizationFilter.cs

當然這里的過濾器只是一個入口,相關的驗證并不是在這里實現的。而是在Antiforgery這個項目上,其實說這個模塊可能會更貼切一些。

由于是面向接口的編程,所以要知道具體的實現,就要找到對應的實現類才可以。

在Antiforgery這個項目中,有這樣一個擴展方法AntiforgeryServiceCollectionExtensions,里面告訴了我們相對應的實現是DefaultAntiforgery這個類。其實Nancy的源碼看多了,看一下類的命名就應該能知道個八九不離十。

 services.TryAddSingleton<IAntiforgery, DefaultAntiforgery>();

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

好了,回歸正題!要驗證是否是合法的請求,自然要先拿到要驗證的內容。

 var tokens = await _tokenStore.GetRequestTokensAsync(httpContext);

它是從Cookie中拿到一個指定的前綴為.AspNetCore.Antiforgery.的Cookie,并根據這個Cookie進行后面相應的判斷。下面是驗證的具體實現:

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;
}

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

如何使用

前面粗略介紹了一下其內部的實現,下面再用個簡單的例子來看看具體的使用情況:

使用一:常規的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的隱藏域:

怎么在ASP.NET Core中對CSRF進行處理

再來看看cookie的相關信息:

怎么在ASP.NET Core中對CSRF進行處理

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

怎么在ASP.NET Core中對CSRF進行處理

使用二: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(); 
 });
})

這樣子的寫法也是和上面的結果是一樣的!

怕的是出現下面這樣的寫法:

$.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);
 }
});

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

怎么在ASP.NET Core中對CSRF進行處理

相信大家也都發現了問題的所在了!!隱藏域的相關內容并沒有一起post過去!!

處理方法有兩種:

方法一:

在data中加上隱藏域相關的內容,大致如下:

$.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);
 }
 });
});

這樣就能處理上面出現的問題了!

使用三:自定義相關信息

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

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

在Startup的ConfigureServices方法中,添加下面的內容即可對默認的名稱進行相應的修改。

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

相應的,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表單:

怎么在ASP.NET Core中對CSRF進行處理

Cookie:

怎么在ASP.NET Core中對CSRF進行處理

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

苍南县| 楚雄市| 永川市| 丹巴县| 苗栗市| 游戏| 福泉市| 自治县| 昌黎县| 成都市| 无锡市| 洛隆县| 洛宁县| 中超| 平武县| 积石山| 景德镇市| 浪卡子县| 伊通| 双辽市| 西峡县| 锦州市| 山东省| 荔浦县| 安顺市| 双柏县| 安岳县| 华蓥市| 南宁市| 济南市| 铁力市| 同仁县| 临武县| 长岛县| 达尔| 景洪市| 萍乡市| 高碑店市| 敦煌市| 五河县| 南华县|