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()';
    }]);
  • 相关阅读:
    Spring IoC容器的设计——BeanFactory应用场景2
    Spring IoC容器的设计——BeanFactory应用场景
    jQuery学习备忘
    Spring IoC容器的设计—3—次线
    Spring IoC容器的设计—2—主线
    Spring IoC容器的设计—1—主线
    关于备忘信息重置解决方案
    E45: 'readonly' option is set (add ! to override)
    未知高度元素居中
    background
  • 原文地址:https://www.cnblogs.com/walkerwang/p/3554486.html
Copyright © 2011-2022 走看看