简介

  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上钩,给自己转账。

  网站源码:

<html><head><metahttp-equiv="Content-Type"content="text/html; charset=gb2312" /> <title></title></head><body><div>我是一个内容丰富的网站,你不会关闭我!</div><iframename="frame"src="invalid.html"sandbox="allow-same-origin allow-scripts allow-forms"style="display: none; width: 800px; height: 1000px;"> </iframe> <scripttype="text/javascript">setTimeout("self.location.reload();",10000);</script></body></html>

    伪造请求源码:

<html><head><title></title></head><body><formid="theForm"action="http://localhost:22699/Home/Transfer"method="post"><inputclass="form-control"id="TargetUser"name="TargetUser"placeholder="用户名"type="text"value="God" /><inputclass="form-control"id="Amount"name="Amount"placeholder="转账金额"type="text"value="100" /></form><scripttype="text/javascript">document.getElementById('theForm').submit();</script></body></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代码:

$(function() {var token = $('@Html.AntiForgeryToken()').val();$('#btnSubmit').click(function() {var targetUser = $('#TargetUser').val();var amount = $('#Amount').val();var data = { 'targetUser': targetUser, 'amount': amount };return$.ajax({url:'@Url.Action("Transfer2", "Home")',type:'POST',data: JSON.stringify(data),contentType:'application/json',dataType:'json',traditional:'true',beforeSend:function(xhr) {xhr.setRequestHeader('__RequestVerificationToken', token);},success:function() {window.location= '@Url.Action("Index", "Home")';}});});});

  在服务端,参考ValidateAntiForgeryTokenAttribute,编写一个AjaxValidateAntiForgeryTokenAttribute:

[AttributeUsage(AttributeTargets.Class |AttributeTargets.Method)]public classAjaxValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter{public voidOnAuthorization(AuthorizationContext filterContext){if (filterContext == null){throw new ArgumentNullException("filterContext");}var request =filterContext.HttpContext.Request;var antiForgeryCookie =request.Cookies[AntiForgeryConfig.CookieName];var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;var formToken = request.Headers["__RequestVerificationToken"];AntiForgery.Validate(cookieValue, formToken);}}

  然后调用时把ValidateAntiForgeryToken替换成AjaxValidateAntiForgeryToken。

  

  大功告成,好有成就感!

全局处理

  如果所有的操作请求都要加一个ValidateAntiForgeryToken或者AjaxValidateAntiForgeryToken,不是挺麻烦吗?可以在某个地方统一处理吗?答案是阔仪的。

  ValidateAntiForgeryTokenAttribute继承IAuthorizationFilter,那就在AuthorizeAttribute里做统一处理吧。

  ExtendedAuthorizeAttribute:

public classExtendedAuthorizeAttribute : AuthorizeAttribute{public override voidOnAuthorization(AuthorizationContext filterContext){PreventCsrf(filterContext);base.OnAuthorization(filterContext);GenerateUserContext(filterContext);}/// <summary>/// http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages/// </summary>private static voidPreventCsrf(AuthorizationContext filterContext){var request =filterContext.HttpContext.Request;if (request.HttpMethod.ToUpper() != "POST"){return;}var allowAnonymous = HasAttribute(filterContext, typeof(AllowAnonymousAttribute));if(allowAnonymous){return;}var bypass = HasAttribute(filterContext, typeof(BypassCsrfValidationAttribute));if(bypass){return;}if(filterContext.HttpContext.Request.IsAjaxRequest()){var antiForgeryCookie =request.Cookies[AntiForgeryConfig.CookieName];var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;var formToken = request.Headers["__RequestVerificationToken"];AntiForgery.Validate(cookieValue, formToken);}else{AntiForgery.Validate();}}private static boolHasAttribute(AuthorizationContext filterContext, Type attributeType){return filterContext.ActionDescriptor.IsDefined(attributeType, true) ||filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(attributeType,true);}private static voidGenerateUserContext(AuthorizationContext filterContext){var formsIdentity = filterContext.HttpContext.User.Identity asFormsIdentity;if (formsIdentity == null || string.IsNullOrWhiteSpace(formsIdentity.Name)){UserContext.Current= null;return;}UserContext.Current= newWebUserContext(formsIdentity.Name);}}

  

  然后在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


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

跨站请求伪造(CSRF/XSRF)相关推荐

  1. .NET Core实战项目之CMS 第十四章 开发篇-防止跨站请求伪造(XSRF/CSRF)攻击处理...

    通过 ASP.NET Core,开发者可轻松配置和管理其应用的安全性. ASP.NET Core 中包含管理身份验证.授权.数据保护.SSL 强制.应用机密.请求防伪保护及 CORS 管理等等安全方面 ...

  2. 跨站请求伪造(CSRF)-简述

    跨站请求伪造(CSRF)-简述 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 ...

  3. 带你刷burpsuite官方网络安全学院靶场(练兵场)之客户端漏洞——跨站请求伪造(CSRF)专题

    介绍 PortSwigger是信息安全从业者必备工具burpsuite的发行商,作为网络空间安全的领导者,他们为信息安全初学者提供了一个在线的网络安全学院(也称练兵场),在讲解相关漏洞的同时还配套了相 ...

  4. django16: csrf跨站请求伪造/CSRF相关装饰器

    CSRF 即跨站请求攻击 跨站请求伪造csrf钓鱼网站本质搭建一个跟正常网站一模一样的页面用户在该页面上完成转账功能转账的请求确实是朝着正常网站的服务端提交唯一不同的在于收款账户人不同给用户书写for ...

  5. csrf防御 php,跨站请求伪造CSRF的防御实例(PHP版本)

    跨站请求伪造CSRF的防御:One-Time Tokens(不同的表单包含一个不同的伪随机值) 在实现One-Time Tokens时,需要注意一点:就是"并行会话的兼容".如果用 ...

  6. 浅谈跨站请求伪造(CSRF)

    浅谈跨站请求伪造(CSRF)   这里简单的记录一下CSRF漏洞~~ 什么是CSRF?   CSRF(Cross-Site Request Forgery,跨站点伪造请求)是一种网络攻击方式,该攻击可 ...

  7. Nginx配置valid_referer解决跨站请求伪造(CSRF)

    Nginx配置valid_referer解决跨站请求伪造(CSRF) 文章目录 Nginx配置valid_referer解决跨站请求伪造(CSRF) 漏洞说明 漏洞描述 危害等级 修复建议 漏洞复现 ...

  8. 跨站请求伪造CSRF防护方法

    CSRF(Cross-site request forgery跨站请求伪造,也被称成为"one click attack"或者session riding,通常缩写为CSRF或者X ...

  9. 跨站请求伪造(CSRF)+ 跨站脚本攻击(XSS)

    一.CSRF 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 X ...

  10. 跨站请求伪造——CSRF

    目录 csrf与xss的区别 CSRF的介绍 利用过程 实战 靶场下载 过程 一.A用户登录浏览器执行动作 二.B用户抓包制作csrf请求页面 三.本地保存 四.制作钓鱼网站 csrf 防御 csrf ...

最新文章

  1. 马斯克发布脑机接口系统!芯片直连大脑,激光开颅放置,可用iPhone操控,网友炸了:这就是黑客帝国...
  2. 2016年第7本:非暴力沟通
  3. 1.14 梯度检验应用的注意事项-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  4. python怎么把cpu占满_如何增加python CPU使用率
  5. c++内存,堆和栈的区别
  6. 【转】自然语言系列学习之表示学习与知识获取(二)word2vec
  7. matplotlib 雷达图2
  8. zabbix—自动发现端口并监控
  9. CCF大专委2019年大数据发展趋势预测
  10. CentOS 6.4 yum安装LAMP环境
  11. Windows10 Kafka Docker 集群搭建
  12. Android JNI(实现自己的JNI_OnLoad函数)
  13. 增加javascript的trim函数
  14. xmake经验总结1:解决c++ future/promise抛出std::system_error的问题
  15. java回溯_java实现回溯算法
  16. php右侧弹窗QQ客服,网页右侧悬浮滚动在线qq客服代码示例_javascript技巧
  17. 父母为双方结婚购置房屋出资,房屋归属
  18. php v8js 执行外部js,php运行jsv8引擎
  19. android然后让list刷新到底部,Android笔记之:App列表之下拉刷新的使用
  20. QT程序到arm板(s5pv210)的移植之旅

热门文章

  1. Linux SSH Publickey登录
  2. Linux挂载命令mount详解
  3. python第七天--字符串的方法与注释
  4. Event Logging 技术简介(转载)
  5. js 操作cookies 方法
  6. iPhone Development Blog系列: 如何制作服务条例窗口
  7. 云计算的关键特点及挑战
  8. 每扇区2048字节的U盘乱码的数据恢复
  9. C# 正则表达式编写及验证方法
  10. 太神奇了!使用C#实现自动核验健康码:(1)二维码识别