CSRF在ASP.NET Core中的处理方法详解(2)

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 action="/home/antiform" method="post"> @Html.AntiForgeryToken() <p><input type="text" /></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的隐藏域:

CSRF在ASP.NET Core中的处理方法详解

再来看看cookie的相关信息:

CSRF在ASP.NET Core中的处理方法详解

可以看到,一切都还是按照前面所说的执行。在输入框输入信息并点击按钮也能正常显示我们输入的文字。

CSRF在ASP.NET Core中的处理方法详解

使用二:Ajax提交

表单:

<form action="/home/antiajax" method="post"> @Html.AntiForgeryToken() <p><input type="text" /></p> <p><input type="button" 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错误):

CSRF在ASP.NET Core中的处理方法详解

相信大家也都发现了问题的所在了!!隐藏域的相关内容并没有一起post过去!!

处理方法有两种:

方法一:

在data中加上隐藏域相关的内容,大致如下:

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

方法二:

在请求中添加一个header

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdssfw.html