手机版

ASP.NET芯CSRF加工方法详解

时间:2021-08-31 来源:互联网 编辑:宝哥软件园 浏览:

前言

几天前,一个朋友问我关于防伪的问题。因为对这一块理解不深,就去研究梳理了一下。

在梳理之前,你需要对背景知识有一个简单的了解。

防伪Token可以说是治疗/预防CSRF的一种治疗方案。

那么什么是CSRF?

CSRF(跨站请求伪造)是一种跨站请求伪造,也称为一键攻击或会话骑行,通常缩写为CSRF或XSRF,是一种恶意利用网站的行为。

简单来说,就是有人盗用你的身份,以你的名义发送恶意请求。

近年来,CSRF处于不温不火的状态,但我们应该小心这一点!

更多详情,请参考维基百科:跨网站请求伪造

下面从使用的角度分析CSRF在ASP.NET CORE的处理。个人认为,主要有以下两个区块

视图级别控制器级别视图级别

使用

@Html的用法。视图级别的AntiForgeryToken()相对简单,它仍然使用HtmlHelper的东西集。将这句话添加到表格中。

原理分析

当上述代码添加到表单中时,页面将生成一个隐藏字段,该隐藏字段的值是一个生成的标记,类似于下面的示例

输入名称=' _ _ RequestVerificationToken ' type=' hidden ' value=' cfdj 8 fbn 4 lzsygljpe6q 0 fwvz 8 wdmtgwk 49 ldu 1 xgup 5-5j 4 jlscml _ idoo 3 xdl 5 eoyi _ ms2u x7llsfi 7 asqniix O2 scejvnabf 9v 51 tuzl _ im2s 63 zuipk 4 lcx RPA _ kuudbk-ls4 hd16 pjsrfppj-degc '/其中name=' _ _ requestveribase64编码内容的简单处理结果可以在Base64UrlTextEncoder.cs中找到

上面生成隐藏字段的代码在文件“反伪造扩展”中,这是github上的源代码文件

关键方法如下:

public void WriteTo(TextWriter编写器,HtmlEncoder编码器){ writer。Write('输入名称=\ ' ');编码器。编码(编写器,_ field name);作家。写(' \ '类型=\ '隐藏'值=\ ' ');编码器。Encode(writer,_ request token);作家。写(' \ '/');}挺清楚的!

控制器级别

使用

[验证防伪标识][自动验证防伪标识][忽略防伪标识]

这三个都可以基于类或方法,所以我们只需要将这些属性添加到控制器或动作中。

关于[属性用法(属性目标。类|属性目标。方法,允许多重=假,继承=真)]

本质是Filter,验证上面隐藏字段的值

过滤器实现:验证反伪造令牌水平过滤器和自动验证反伪造令牌水平过滤器

其中,autovalidateantiforytokenautorizationfilter继承了validateantiforytokenautorizationfilter,只重写了ShouldValidate方法。

以下是validateantiforytokenauthorizationfilter的核心方法:

public class validateantiforytokenauthorizationfilter : iasynccauthorizationfilter,ianiforgerypolicy { public async Task on authorizationasync(AuthorizationFilterContext){ if(context==null){ throw new ArgumentNullException(name of(context));} if(is losestantifyrypolicy(context。filters)should validate(context)){ try { await _ antifory。ValidateRequestAsync(上下文。HttpContext);} catch(antiforyvalidationexception异常){ _logger。反伪造令牌无效(异常。消息,异常);语境。result=new BadRequestResult();}}}}完整的实现可以在github源代码中找到:validateantforgefyrtokenauthorizationfilter . cs。

当然,这里的过滤器只是一个入口,相关的验证并没有在这里实现。但在防伪项目上,其实这个模块可能更合适。

因为是面向接口的编程,要知道具体的实现,就要找到对应的实现类。

在防伪这个项目中,有这样一个扩展方法反伪造服务集合扩展,里面告诉了我们相对应的实现是默认防伪这个类。其实南茜的源码看多了,看一下类的命名就应该能知道个八九不离十。

服务尝试添加单一防伪,默认防伪其中还涉及到了IServiceCollection,但这不是本文的重点,所以不会展开讲这个,只是提出它在。净芯中是一个重要的点。

好了,回归正题!要验证是否是合法的请求,自然要先拿到要验证的内容。

var tokens=await _ tokenStore .GetRequestTokensAsync(HttpContext);它是从饼干中拿到一个指定的前缀为。AspNetCore。防伪的饼干,并根据这个饼干进行后面相应的判断。下面是验证的具体实现:

公共bool tryvalidatetoken集(HttpContext HttpContext,AntiforgeryToken cookieToken,AntiforgeryToken requestToken,out string message){ //去掉了部分非空的判断//令牌的格式是否正确?if(!cookieToken .IsCookieToken | | requestToken .iskokietoken){消息=资源.反伪造令牌_令牌已映射;返回false} //嵌入每个传入令牌中的安全令牌是否相同?if(!对象等于.安全令牌,请求令牌.SecurityToken)){ 0消息=资源。反伪造_ SecurityTokenMismatch返回false} //传入的令牌是给当前用户的吗?var currentUsername=字符串。空的;binary BloB CurrentClaimID=nullvar authenticatediidentity=getauthenticatediidentity(HttpContext .用户);if(authenticated identity!=null){ CurrentClaimIdMuid=GetClaimIdBlob(_ ClaimIdextractor .extraclaimuid(HttpContext .用户));if(currentclaimid==null){ currentUsername=authenticatediidentity .名字?字符串。空的;} } //OpenID和其他类似的身份验证方案使用URIs作为用户名。//这些应该区分大小写var comparer=StringComparer .普通案例;if (currentUsername .以(' http://'开头,StringComparison .ordinaligorcase)| | currentUsername .以(' https://'开头,StringComparison .ordinalignorcase)){ comparer=string comparer .序数;} if(!比较器等于(请求令牌.用户名,当前用户名)){消息=资源formatanforgerytoken _ UsernameMismatch(请求令牌.用户名,currentUsername);返回false} if(!对象等于(请求令牌.ClaimUid,currentClaimUid)){消息=资源.反伪造_ ClaimUidMismatch返回false} //附加数据有效吗?if (_additionalDataProvider!=null!_additionalDataProvider .ValidateAdditionalData(httpContext,requestToken .额外的数据){消息=资源。反伪造失败;返回false}消息=null返回真;}注:验证前还有一个反序列化的过程,这个反序列化就是从饼干中拿到要判断的cookietoken和requesttoken

如何使用

前面粗略介绍了一下其内部的实现,下面再用个简单的例子来看看具体的使用情况:

使用一:常规的形式表单

先在视图添加一个形式表单

form id=' form 1 ' action='/home/anti form ' method=' post ' @ Html .反伪造Token() pinput类型=' text ' name=' message '/p pinput类型='submit '值='按表单发送/p/表单在控制器添加一个行动

[validateantiforytoken][httpset]public IActionResult反表单(字符串消息){返回内容(消息);}来看看生成的超文本标记语言是不是如我们前面所说,将@Html .防伪令牌()输出为一个名字为__RequestVerificationToken的隐藏域:

再来看看甜饼干的相关信息:

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

使用二:Ajax提交

表单:

form id=' form 2 ' action='/home/anti jax ' method=' post ' @ Html .antiforrytoken()pinput类型=' text ' name=' message ' id=' AJaxmsg '/p pinput类型=' button ' id=' btnAjax '值='通过Ajax发送'/p/formjs :

$(function () { $('#btnAjax ')。on('click ',function () { $('#form2 ')。submit();});})这种写法和上面的结果是一样的!

我害怕下面的文字:

$.ajax({ type: 'post ',dataType: 'html ',url: '@Url。Action('AntiAjax ',' Home '),data : { message : $(' # AJaxmsg ')。val() },success:函数(结果){ alert(结果);},error:函数(err,scnd){ alert(err . statustext);}});这样,在正常情况下,您看不到任何问题,但实际结果如下(400个错误):

相信大家都发现问题了!隐藏域的相关内容没有一起发帖!

有两种治疗方法:

方法1:

将与隐藏字段相关的内容添加到数据中,大致如下:

$.Ajax({//data : { message : $(' # AJaxmsg '))。val(),_ _ RequestVerificationToken : $(' input[name=' _ _ RequestVerificationToken ']')。val()} });方法2:

向请求添加标题

$('#btnAjax ')。on('click ',function(){ var token=$(' input[name=' _ _ RequestVerificationToken ']')。val();$.ajax({ type: 'post ',dataType: 'html ',url: '@Url。Action('AntiAjax ',' Home '),data : { message : $(' # AJaxmsg ')。val() },header RS : { ' RequestVerificationToken ' : token },success:函数(结果){ alert(结果);},error:函数(err,scnd){ alert(err . statustext);} });});这样,我们就可以处理上述问题了!

使用3:自定义相关信息

可能有很多人认为生成的隐藏域的名称可以用自己的替换,cookie的名称可以用自己的替换

答案是肯定的,让我们简单演示一下:

在启动的配置服务方法中,添加以下内容以相应地修改默认名称。

服务。添加防伪(选项={ option。CookieName=' CUSTOMER-CSRF-COOKIE ';选项。formfield name=' CustomerFieldName ';选项。HEADER name=' CUSTOMER-CSRF-HEADER ';});因此,ajax请求也应该修改:

var token=$(' input[name=' CustomerFieldName ']')。val();//隐藏字段的名称应改为$。Ajax ({type:' post '、datatype3360' html '、url3360' @ url.action ('anti Ajax '、' home '))、data : { message : $(' # Ajax msg '). val . Headers : { ' customer-csrf-header ' : token//注意,该头需要修改},success : function(result){ alert(result);},error:函数(err,scnd){ alert(err . statustext);}});效果如下:

表单表单:

Cookie:

本文涉及的相关项目:

关于CSRF相关内容的声明

防止ASP.NET核心区的跨站点请求伪造(XSRF/CSRF)攻击

论CSRF攻击模式

摘要

以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。

版权声明:ASP.NET芯CSRF加工方法详解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。