Introduction
To prevent Cross-Site Request Forgery (CSRF) Attacks we use ASP.NET MVC’s AntiForgeryToken. It generates a hidden form field (anti-forgery token) that is validated when the form is submitted. It is work fine with normal form submittion but It is not work with $http post with angular or $.post with jquery. This article will be helpful to validate AntiForgeryToken with $http (angularjs) by creating custom validator.
Description
I) Create Filter/Attribute 'CustomValidateAntiForgeryToken':
We will process the request, extract the tokens from the request header. Then call the AntiForgery.Validate method to validate the tokens. The Validate method throws an exception if the tokens are not valid. We create a custom attribute for this. Right click on Filters folder and add new class “CustomValidateAntiForgeryToken.cs”
using System;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
namespace EventCombo.ActionFilters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CustomValidateAntiForgeryToken : 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 static string GetAntiForgeryToken()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
try
{
ValidateRequestHeader(filterContext.HttpContext.Request);
}
catch (HttpAntiForgeryException ex)
{
throw new HttpAntiForgeryException("Anti forgery token cookie not found. Error: " + ex.Message);
}
}
}
}
In the above class we can see a static method GetAntiForgeryToken. We will use it to generate token later.
II) In Angular View
Add a hidden field with value as Antiforgery token generated by GetAntiForgeryToken method:
<form name="personalInfoForm" novalidate>
<input id="antiForgeryToken" data-ng-model="AntiForgeryToken" type="hidden" data-ng-init="AntiForgeryToken='@CustomValidateAntiForgeryToken.GetAntiForgeryToken()'" />
III) In Angular Service JS
Use hidden field model to set header:
this.updateMyAccount = function (UserDetail, $scope) {
var response = $http({
method: "post",
datatype: "data.json",
data: { myAccount: UserDetail },
url: "/Account/UpdateAccountDetail",
headers: {
'RequestVerificationToken': $scope.AntiForgeryToken,
}
});
return response;
};
IV) In MVC Action
Put custom attribute 'CustomValidateAntiForgeryToken':
[HttpPost]
[Authorize]
[CustomValidateAntiForgeryToken]
public ActionResult UpdateAccountDetail(MyAccountViewModel myAccount)
{
V) Now Build and test. That's it.
Conclusion
We have seen see how to genrate and validate AntiForgeryToken with angular js. It is very useful when we are working in architecture way where we can’t access value of controls in Ajax request directly.
This method to prevent CSRF does not work in my project, my application throws exception:
System.Web.Mvc.HttpAntiForgeryException: 'Anti forgery token cookie not found. Error: The required anti-forgery cookie "__RequestVerificationToken" is not present.'
Did someone try this method in own project ?
Marcin
23-Jul-2017 at 04:54