手机版

浅谈ASP.NET MVC防止跨站点请求伪造(CSRF)攻击的实现方法

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

在HTTP POST请求中,我们多次查看了视图和控制器中的以下代码:

1.Html。在1.View中调用了反伪造Token()

2.在2.Controller中的方法中添加了[validateantiforytoken]注释

这种看似成对的书写实际上是为了避免引入跨站点请求伪造(CSRF)攻击。

这种攻击直到2001年才被承认。2006年,美国在线视频租赁网站网飞爆发了多个CSRF漏洞。2008年,一个受欢迎的视频网站YouTube遭到CSRF的攻击。同年,一名墨西哥银行客户遭到CSRF攻击,杀毒软件供应商迈克菲也爆发了CSRF攻击(引自维基百科)。

之所以很多大型网站也受到CSRF的攻击,是因为CSRF攻击本身的过程比较长,很多开发者可能好几年都不会遇到CSRF的攻击,所以他们对CSRF的认知比较模糊,没有引起足够的重视。

CSRF攻击仿真实例

我们将通过一个模拟的例子来解释CSRF的攻击原理,然后回头看看MVC提供的安全策略。

看似安全的银行转账页面

假设我们是银行的Web开发人员,现在需要写一个转账页面。客户登录后,在这里输入对方账号和转账金额,即可实现转账:

[Authorize]public action result transfer money(){ return View();} [http post] [authorize]公开行动结果转账(字符串到账户,int money){//这里是转账业务代码ViewBag。ToAccount=ToAccount视图包。金钱=金钱;返回视图();}因为这个过程需要认证,所以我们对TransferMoney的两种操作方式进行了【Authorize】标注,防止匿名用户访问。

如果您直接访问http://localhost :55654/home/transfer money,您将跳转到登录页面:

登录后,进入转账页面。让我们看看转移的视图代码:

@{ ViewBag。标题='转账';} H2 transfer Money/H2 @ if(viewpag。ToAccount==null){使用(Html。begin inform()){ Input type=' text ' name=' to account '/Input type=' text ' name=' money '/Input type=' submit ' value=' transfer '/} } else { @ :您已经转移了[@ viewpag。钱]元到账号【@ ViewBag。ToAccount]!}视图代码中有一个逻辑判断,根据是否是ViewBag显示不同的内容。目标帐户是否为空:

1.如果1。ToAccount为空,表示是页面访问。

2.如果2。视图包. ToAccount不为空,转账成功,需要显示转账成功的提示信息。

让我们来看看页面运行效果:

功能完成!似乎没有问题,但CSRF还有另一个漏洞,它是隐藏的,很难找到。

我是黑客,给我看看钱

这里有两个角色,银行的客户和黑客。

黑客b在银行发现了这个漏洞,写了两个简单的页面,第一页(click_me_please.html):

!DOCTYPE html html head meta http-equiv=' Content-Type ' Content=' text/html;charset=utf-8 '/head body哈哈,开玩笑!iframe frame border=' 0 ' style=' display : none;'Src=' http:/click _ me _请_iframe.html '/iframe/body/html第一页只包含一个隐藏的iframe标记,该标记指向第二页(click _ me _请_ iframe . html):

!DOCTYPE html html head meta http-equiv=' Content-Type ' Content=' text/html;charset=utf-8 '/head body on load=' document . getelementbyid(' my form 1 ')。提交();'form method=' POST ' id=' my form 1 ' action=' http://localhost :55654/Home/Transfer money '输入类型=' hidden ' name=' to account ' value=' 9999999 '输入类型=' hidden ' name=' money ' value=' 3000 '/form/body/html第二页标有表单标签,其中放置黑客自己的银行账号和转账金额,在页面上打开

现在黑客把这两页放到了公共网络上:

http://fineui.com/demo_mvc/csrf/click_me_please.html

然后分批给用户发送带有攻击链接的邮件,银行的客户A刚登录银行系统点击了这个链接:

然后你会看到这一页:

你可能会在心里想,谁这么无聊,然后心情郁闷地合上这一页。之后,客户A会更加郁闷,因为黑客B的银行账号【99999999】成功增加了3000元!

怎么转账,没有认证吗

是的,传输需要身份验证。现在的问题是,你已经登录了银行系统,完成了身份验证,并在浏览器的新选项卡中打开了黑客的链接。让我们看看发生了什么:

这里有三个HTTP请求,第一个是【逗你】页面,第二个是里面的IFrame页面,第三个是IFrame加载后发起的POST请求,也就是具体的转移页面。因为IFrame是隐藏的,用户不知道发生了什么。

让我们具体看看第三个请求:

很明显,这个传输是成功的,Cookie携带了用户认证信息,所以所有后台根本不知道这个请求是来自黑客的页面,成功传输返回:

如何防止CSRF袭击

从上面的例子可以看出,CSRF源于表单认证的实现机制。

因为HTTP本身是无状态的,这意味着每一个请求对Web服务器来说都是全新的,而服务器并不知道之前请求的任何状态,所以认证要求我们在第二次访问时知道是否登录(不可能每次请求都验证账号密码),这本身就是一个矛盾!

这个矛盾的解决方案是cookie,它可以在浏览器中保存少量信息,所以Forms Authentication使用cookie来保存加密的身份信息。存储在Cookie中的所有值将在每个HTTP请求中发送到服务器(无论是GET还是POST,静态资源还是动态资源),这给了CSRF一个机会。

因此,CSRF的根源在于,服务器可以从Cookie中获取身份验证信息,但无法知道这个HTTP请求是否真的是用户发起的。

推荐人认证

Referer是HTTP请求头信息的一部分。每当浏览器向服务器发送一个请求时,它将伴随着Referer信息,指示发起请求的当前页面地址。

对于正常的传输请求,我们可以看到Referer和浏览器地址栏是一致的:

我们来看看刚才的黑客页面:

您可以看到Referer的内容与当前发起请求的页面地址相同。注意比较:

1.浏览器网址:点击我请

2.HTTP请求地址:家庭/转账

3.推荐人:点击我请iframe.html,注意这是发起请求的页面,不一定是浏览器地址栏中显示的网址。

基于这一原则,我们可以简单地通过推荐者来验证转移的POST请求:

[httpset][Authorize]公共操作结果转移货币(字符串到帐户,整数货币){ if(请求。网址.主机!=请求。UrlReferrer.Host) {引发新异常(' Referrer验证失败!');}//放转账业务代码ViewBag。ToAccount=此处为to account;视图包。金钱=金钱;返回视图();}此时访问http://fineui.com/demo_mvc/csrf/click_me_please.html时,恶意转账失败:

默认情况下,MVC支持CSRF身份验证

MVC提供的CSRF认证方式默认更彻底,验证当前请求是否真的来自用户的操作。

在视图页面上,调用Html。表单内部增加了反伪造令牌功能:

@ if(viewpag。ToAccount==null){使用(Html。begin inform()){ @ Html。反伪造Token()输入类型='text' name='ToAccount' /输入类型=' text ' name=' money '/输入类型=' submit ' value=' transfer '/} } else { @ :您已经转移了[@ viewpag。钱]元到账号【@ ViewBag。ToAccount]!}这将分别在表单标签和Cookie中生成名为__RequestVerificationToken的令牌:

然后在控制器方法中添加一个[validateantforgerytoken]注释:

[http post][authorize][validateandforgerytoken]公开行动结果转账(字符串到账户,int money){//这里是转账业务代码ViewBag。ToAccount=ToAccount视图包。金钱=金钱;返回视图();}在服务器端,会验证这两个Token是否一致(不相等),如果不一致,会报错。

下面,手动修改表单中该隐藏字段的值,以查看错误提示:

以类似的方式,运行黑客页面的http://fineui.com/demo_mvc/csrf/click_me_please.html,恶意传输失败:

此时,虽然Cookie中的__RequestVerificationToken被提交到后台,但黑客无法知道表单字段中__RequestVerificationToken的值,因此传输失败。

以上关于ASP.NET MVC防止跨站点请求伪造(CSRF)攻击的实现方法的讨论,都是边肖分享的内容,希望能给大家一个参考和支持。

版权声明:浅谈ASP.NET MVC防止跨站点请求伪造(CSRF)攻击的实现方法是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。