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()';
}]);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM