zoukankan      html  css  js  c++  java
  • asp.net MVC中防止跨站请求攻击(CSRF)的ajax用法

    参考:

    Preventing Cross-Site Request Forgery (CSRF) Attacks
    Validating .NET MVC 4 anti forgery tokens in ajax requests

    在mvc中,微软提供了一个简单的方法来防止CSRF,就是在前端form表单里加上Anti-Forgery Tokens

    <form action="/Home/Test" method="post">
        <input name="__RequestVerificationToken" type="hidden"   
               value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />    
        <input type="submit" value="Submit" />
    </form>

    razor的写法很简单:

    @using (Html.BeginForm("Manage", "Account")) {
        @Html.AntiForgeryToken()
    }

    后端只需要在action上加上[ValidateAntiForgeryToken]标签即可

    //
    // POST: /execute/uploadfile/
    [HttpPost]
    [MyValidateAntiForgeryToken]
    public ActionResult UploadFile()
    {
    	// codes here
    }

    那么ajax请求呢?
    首先,我尝试在header里面加了__RequestVerificationToken,值就从razor生成,结果报错,最终发现还是要自定义,默认的[ValidateAntiForgeryToken]不行,所以我们就自定义一个MyValidateAntiForgeryTokenAttribute(片段1),需要注意以下几点:

    • 从filter中自己判断请求是不是ajax请求,如果你确实发起了ajax请求,还被Reauest.IsAjaxRequest()方法判定为false,那么检查一下header里面有没有{"X-Requested-With" : "XMLHttpRequest"}这个键和值
    • 既然是自定义过滤了,那么header里面这个键就没必要非得是__RequestVerificationToken了,你可以任意自定义,只要前后对应即可。
    • 至于如何取值,上面介绍了用@html扩展的写法,然后用js的方法把值取出来,也可以用下面片段2的写法,直接用razor写到js里面去,片段3中有使用方法(本例中一个angular的例子,注意甄别)
    • 最后,在应用的action前把系统默认的标签改成我们自定义的即可。

    片段1,自定义的anti csrf过滤器

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class MyValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
    {
        private void ValidateRequestHeader(HttpRequestBase request)
        {
            string cookieToken = String.Empty;
            string formToken = String.Empty;
            string tokenValue = request.Headers["RequestVerificationToken"];
            if (!String.IsNullOrEmpty(tokenValue))
            {
                string[] tokens = tokenValue.Split(':');
                if (tokens.Length == 2)
                {
                    cookieToken = tokens[0].Trim();
                    formToken = tokens[1].Trim();
                }
            }
            AntiForgery.Validate(cookieToken, formToken);
        }
    
        public void OnAuthorization(AuthorizationContext filterContext)
        {
    
            try
            {
                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {
                    ValidateRequestHeader(filterContext.HttpContext.Request);
                }
                else
                {
                    AntiForgery.Validate();
                }
            }
            catch (HttpAntiForgeryException e)
            {
                throw new HttpAntiForgeryException("Anti forgery token cookie not found");
            }
        }
    }

    片段2,定义一个@function片断

    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;
        }
    }

    片段3, 使用定义的@function片断(实例为angular中为http请求添加全局的header)

    var app = angular.module('srv', ['angularLocalStorage', 'angularFileUpload']);
    app.config(['$httpProvider', function($httpProvider) {
    	$httpProvider.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
    	$httpProvider.defaults.headers.common["RequestVerificationToken"] = '@TokenHeaderValue()';
    }]);
  • 相关阅读:
    [Asp.net 开发系列之SignalR篇]专题四:使用SignalR实现发送图片
    [Asp.net 开发系列之SignalR篇]专题三:使用SignalR实现聊天室的功能
    [Asp.net 开发系列之SignalR篇]专题二:使用SignalR实现酷炫端对端聊天功能
    [Asp.net 开发系列之SignalR篇]专题一:Asp.net SignalR快速入门
    [后端人员耍前端系列]Bootstrap篇:30分钟快速掌握Bootstrap
    工欲善其事,必先利其器
    ASP.NET 开发必备知识点(2):那些年追过的ASP.NET权限管理
    ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上
    [你必须知道的NOSQL系列]专题二:Redis快速入门
    [你必须知道的NOSQL系列]专题一:MongoDB快速入门
  • 原文地址:https://www.cnblogs.com/walkerwang/p/3554486.html
Copyright © 2011-2022 走看看