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)