Web安全相关(二):跨站请求伪造(CSRF/XSRF)
简介
CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
场景
某程序员大神God在某在线银行Online Bank给他的朋友Friend转账。
转账后,出于好奇,大神God查看了网站的源文件,以及捕获到转账的请求。
大神God发现,这个网站没有做防止CSRF的措施,而且他自己也有一个有一定访问量的网站,于是,他计划在自己的网站上内嵌一个隐藏的Iframe伪造请求(每10s发送一次),来等待鱼儿Fish上钩,给自己转账。
网站源码:
1 <html>
2 <head>
3 <metahttp-equiv="Content-Type"content="text/html; charset=gb2312" />
4 <title></title>
5 </head>
6 <body>
7 <div>
8 我是一个内容丰富的网站,你不会关闭我!9 </div>
10
11 <iframename="frame"src="invalid.html"sandbox="allow-same-origin allow-scripts allow-forms"style="display: none; width: 800px; height: 1000px;"> </iframe>
12 <scripttype="text/javascript">
13 setTimeout("self.location.reload();",10000);14 </script>
15 </body>
16 </html>
伪造请求源码:
1 <html>
2 <head>
3 <title></title>
4 </head>
5 <body>
6 <formid="theForm"action="http://localhost:22699/Home/Transfer"method="post">
7 <inputclass="form-control"id="TargetUser"name="TargetUser"placeholder="用户名"type="text"value="God" />
8 <inputclass="form-control"id="Amount"name="Amount"placeholder="转账金额"type="text"value="100" />
9 </form>
10
11 <scripttype="text/javascript">
12 document.getElementById('theForm').submit();13 </script>
14 </body>
15 </html>
鱼儿Fish打开了大神God的网站,在上面浏览丰富多彩的内容。此时伪造请求的结果是这样的(为了演示效果,去掉了隐藏):
因为鱼儿Fish没有登陆,所以,伪造请求一直无法执行,一直跳转回登录页面。
然后鱼儿Fish想起了要登录在线银行Online Bank查询内容,于是他登录了Online Bank。
此时伪造请求的结果是这样的(为了演示效果,去掉了隐藏):
鱼儿Fish每10秒会给大神God转账100元。
防止CSRF
CSRF能成功是因为同一个浏览器会共享Cookies,也就是说,通过权限认证和验证是无法防止CSRF的。那么应该怎样防止CSRF呢?其实防止CSRF的方法很简单,只要确保请求是自己的站点发出的就可以了。那怎么确保请求是发自于自己的站点呢?ASP.NET以Token的形式来判断请求。
我们需要在我们的页面生成一个Token,发请求的时候把Token带上。处理请求的时候需要验证Cookies+Token。
此时伪造请求的结果是这样的(为了演示效果,去掉了隐藏):
$.ajax
如果我的请求不是通过Form提交,而是通过Ajax来提交,会怎样呢?结果是验证不通过。
为什么会这样子?我们回头看看加了@Html.AntiForgeryToken()后页面和请求的变化。
1. 页面多了一个隐藏域,name为__RequestVerificationToken。
2. 请求中也多了一个字段__RequestVerificationToken。
原来要加这么个字段,我也加一个不就可以了!
啊!为什么还是不行...逼我放大招,研究源码去!
噢!原来token要从Form里面取。但是ajax中,Form里面并没有东西。那token怎么办呢?我把token放到碗里,不对,是放到header里。
js代码:
1 $(function() {2 var token = $('@Html.AntiForgeryToken()').val();3
4 $('#btnSubmit').click(function() {5 var targetUser = $('#TargetUser').val();6 var amount = $('#Amount').val();7 var data = { 'targetUser': targetUser, 'amount': amount };8 return$.ajax({9 url: '@Url.Action("Transfer2", "Home")',10 type: 'POST',11 data: JSON.stringify(data),12 contentType: 'application/json',13 dataType: 'json',14 traditional: 'true',15 beforeSend: function(xhr) {16 xhr.setRequestHeader('__RequestVerificationToken', token);17 },18 success:function() {19 window.location = '@Url.Action("Index", "Home")';20 }21 });22 });23 });
在服务端,参考ValidateAntiForgeryTokenAttribute,编写一个AjaxValidateAntiForgeryTokenAttribute:
1 [AttributeUsage(AttributeTargets.Class |AttributeTargets.Method)]2 public classAjaxValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter3 {4 public voidOnAuthorization(AuthorizationContext filterContext)5 {6 if (filterContext == null)7 {8 throw new ArgumentNullException("filterContext");9 }10
11 var request =filterContext.HttpContext.Request;12
13 var antiForgeryCookie =request.Cookies[AntiForgeryConfig.CookieName];14 var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;15 var formToken = request.Headers["__RequestVerificationToken"];16 AntiForgery.Validate(cookieValue, formToken);17 }18 }
然后调用时把ValidateAntiForgeryToken替换成AjaxValidateAntiForgeryToken。
大功告成,好有成就感!
全局处理
如果所有的操作请求都要加一个ValidateAntiForgeryToken或者AjaxValidateAntiForgeryToken,不是挺麻烦吗?可以在某个地方统一处理吗?答案是可以的。
ValidateAntiForgeryTokenAttribute继承IAuthorizationFilter,那就在AuthorizeAttribute里做统一处理吧。
ExtendedAuthorizeAttribute:
1 public classExtendedAuthorizeAttribute : AuthorizeAttribute2 {3 public override voidOnAuthorization(AuthorizationContext filterContext)4 {5 PreventCsrf(filterContext);6 base.OnAuthorization(filterContext);7 GenerateUserContext(filterContext);8 }9
10 /// <summary>
11 /// http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages
12 /// </summary>
13 private static voidPreventCsrf(AuthorizationContext filterContext)14 {15 var request =filterContext.HttpContext.Request;16
17 if (request.HttpMethod.ToUpper() != "POST")18 {19 return;20 }21
22 var allowAnonymous = HasAttribute(filterContext, typeof(AllowAnonymousAttribute));23
24 if(allowAnonymous)25 {26 return;27 }28
29 var bypass = HasAttribute(filterContext, typeof(BypassCsrfValidationAttribute));30
31 if(bypass)32 {33 return;34 }35
36 if(filterContext.HttpContext.Request.IsAjaxRequest())37 {38 var antiForgeryCookie =request.Cookies[AntiForgeryConfig.CookieName];39 var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;40 var formToken = request.Headers["__RequestVerificationToken"];41 AntiForgery.Validate(cookieValue, formToken);42 }43 else
44 {45 AntiForgery.Validate();46 }47 }48
49 private static boolHasAttribute(AuthorizationContext filterContext, Type attributeType)50 {51 return filterContext.ActionDescriptor.IsDefined(attributeType, true) ||
52 filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(attributeType, true);53 }54
55 private static voidGenerateUserContext(AuthorizationContext filterContext)56 {57 var formsIdentity = filterContext.HttpContext.User.Identity asFormsIdentity;58
59 if (formsIdentity == null || string.IsNullOrWhiteSpace(formsIdentity.Name))60 {61 UserContext.Current = null;62 return;63 }64
65 UserContext.Current = newWebUserContext(formsIdentity.Name);66 }67 }
然后在FilterConfig注册一下。
FAQ:
1. BypassCsrfValidationAttribute是什么鬼?不是有个AllowAnonymousAttribute吗?
如果有些操作你不需要做CSRF的处理,比如附件上传,你可以在对应的Controller或Action上添加BypassCsrfValidationAttribute。
AllowAnonymousAttribute不仅会绕过CSRF的处理,还会绕过认证和验证。BypassCsrfValidationAttribute绕过CSRF但不绕过认证和验证,
也就是BypassCsrfValidationAttribute作用于那些登录或授权后的Action。
2. 为什么只处理POST请求?
我开发的时候有一个原则,查询都用GET,操作用POST,而对于查询的请求没有必要做CSRF的处理。大家可以按自己的需要去安排!
3. 我做了全局处理,然后还在Controller或Action上加了ValidateAntiForgeryToken或者AjaxValidateAntiForgeryToken,会冲突吗?
不会冲突,只是验证会做两次。
源码下载
为了方便使用,我没有使用任何数据库,而是用了一个文件来存储数据。代码下载后可以直接运行,无需配置。
下载地址:https://github.com/ErikXu/CSRF
文章转载自:http://www.cnblogs.com/Erik_Xu/p/5481441.html
转载于:https://www.cnblogs.com/supersnowyao/p/8279186.html
Web安全相关(二):跨站请求伪造(CSRF/XSRF)相关推荐
- Web安全测试---跨站请求伪造CSRF
跨站请求 伪造 (即CSRF )被Web 安全 界称为诸多漏洞中"沉睡的巨人",其威胁程度由此"美誉"便可见一斑.本文将简单介绍该漏洞,并详细说明造成这种漏洞的 ...
- 浅谈跨站请求伪造(CSRF)
浅谈跨站请求伪造(CSRF) 这里简单的记录一下CSRF漏洞~~ 什么是CSRF? CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击可 ...
- 跨站请求伪造(CSRF)-简述
跨站请求伪造(CSRF)-简述 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 ...
- .NET Core实战项目之CMS 第十四章 开发篇-防止跨站请求伪造(XSRF/CSRF)攻击处理...
通过 ASP.NET Core,开发者可轻松配置和管理其应用的安全性. ASP.NET Core 中包含管理身份验证.授权.数据保护.SSL 强制.应用机密.请求防伪保护及 CORS 管理等等安全方面 ...
- csrf防御 php,跨站请求伪造CSRF的防御实例(PHP版本)
跨站请求伪造CSRF的防御:One-Time Tokens(不同的表单包含一个不同的伪随机值) 在实现One-Time Tokens时,需要注意一点:就是"并行会话的兼容".如果用 ...
- Nginx配置valid_referer解决跨站请求伪造(CSRF)
Nginx配置valid_referer解决跨站请求伪造(CSRF) 文章目录 Nginx配置valid_referer解决跨站请求伪造(CSRF) 漏洞说明 漏洞描述 危害等级 修复建议 漏洞复现 ...
- 带你刷burpsuite官方网络安全学院靶场(练兵场)之客户端漏洞——跨站请求伪造(CSRF)专题
介绍 PortSwigger是信息安全从业者必备工具burpsuite的发行商,作为网络空间安全的领导者,他们为信息安全初学者提供了一个在线的网络安全学院(也称练兵场),在讲解相关漏洞的同时还配套了相 ...
- django16: csrf跨站请求伪造/CSRF相关装饰器
CSRF 即跨站请求攻击 跨站请求伪造csrf钓鱼网站本质搭建一个跟正常网站一模一样的页面用户在该页面上完成转账功能转账的请求确实是朝着正常网站的服务端提交唯一不同的在于收款账户人不同给用户书写for ...
- Web安全测试之跨站请求伪造(CSRF)篇
跨站请求伪造(即CSRF)被Web安全界称为诸多漏洞中"沉睡的巨人",其威胁程度由此"美誉"便可见一斑.本文将简单介绍该漏洞,并详细说明造成这种漏洞的原因所在, ...
- 跨站请求伪造CSRF防护方法
CSRF(Cross-site request forgery跨站请求伪造,也被称成为"one click attack"或者session riding,通常缩写为CSRF或者X ...
最新文章
- 单文件浏览器_图文并茂深度解析浏览器渲染原理,包看懂超值得收藏
- 在Ubuntu 14.04 64bit中永久添加DNS的方法
- 使用 JSONP 实现跨域通信,第 2 部分: 使用 JSONP、jQuery 和 Yahoo! 查询语言构建 mashup...
- python函数def中import_在Python中使用def函数时出现名称错误
- java new url 带密码_获取密码重置URL
- 水凝胶 静电纺丝_北理工赵扬ACS Nano:在水凝胶纺织软体机器人方面取得进展
- css实现元素居中的常见方法
- [Linux]NIS: 集中化认证服务
- C#LeetCode刷题-分治算法
- Gradle DSL method not found: ‘compile()’
- Crashlytics功能集成
- iOS12系统图片heic如何在电脑上查看
- dnf外挂java代码,使用Java实现简朴的斗地主案例_rust辅助,绝地求生卡盟
- 如何获得WPA握手包EWSA破解WPA密码教程[zz]
- 微信小程序绘制图表(折线图、柱状图)
- css磨砂效果背景和特殊背景
- 解决 Invalid MEX-file ‘xxx.mexw64‘: 找不到指定的模块 的问题
- 新型企业最重视的评估手段:360评估
- 源码解析 深入vue响应式原理
- win7利用pycharm代码连接夜神模拟器运行appium,被杀进程怎么办
热门文章
- C++之异常处理探究
- 零中频接收机频率转换图_【鼎阳硬件智库原创︱频谱分析仪】频谱分析仪应用解惑之频率分辨力...
- java 捕获 nullpointerexception,Java 空检查链与捕获NullPointerException
- fsck 修复文件系统_微软推出Win10 20H2 Build 19042.608测试版 修复多种已知错误
- matlab 符号表,MATLAB——matlab特殊符号表【转载】
- java 生成一个空文件系统_如何使用java创建一个空白的PPT文档?
- Spring Security HttpSecurity.formLogin
- 1.8 简单卷积网络示例
- opencv-api matchTemplate
- editthiscookie