Table of Contents
- Introduction
- Steps to implementing Antiforgery token through AJAXPOST in MVC [Razor]
- Control Flow
Introduction
Antiforgery token is required where we need to implement CSRF [Cross-Site Request Forgery]. It is a simple trick. In Master page, Get the Token by using server code and store it as global JSON object with property name ‘RequestVerificationToken
’, bind the token to the header of the Ajax post. In server side, create a filter that gets the token by property name ‘RequestVerificationToken
’ and validate. Follow the below steps for better understanding.
Steps to Implementing Antiforgery Token Through AJAXPOST in MVC [Razor]
Step 1: Get Token Value in Master Page Through Server Code
@{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
var tokenHeaderValue = cookieToken + ":" + formToken;
}
cookieToken
: token stored inside the cookie
formToken
: token sent to your page for the forms
AntiForgery.GetTokens();
stores the token value inside the variable ‘cookieToken, formToken
’
Add the above code in your Master page or the page where you require antiforgery token.
Step 2: Assign the Token Value as Global Variable in JQuery
<script type="text/javascript">
var TOKENHEADERVALUE = '@tokenHeaderValue';
</script>
Store ‘@tokenHeaderValue
’ in the Global JQuery variable ‘TOKENHEADERVALUE
’.
Place the above code in page where you placed Step 1 code.
Step 3: Setup the Ajax with Header
$(document).ready(function () {
$.ajaxSetup({
headers: {
'RequestVerificationToken': TOKENHEADERVALUE
},
});
});
Inside $.ajaxSetup({…. });
, place the headers object with property ‘RequestVerificationToken
’ contains the token value from the Global variable ‘TOKENHEADERVALUE
’.
$.ajax({
url: url,type: 'POST',contentType: 'application/json;charset=utf-8', data: dataObj,success: function (data) {alert('Success!');}, error: function(data) { alert('Error!');} });
This ‘$.ajaxSetup({…. });
‘ adds the ‘headers’ as one more property to the above $.ajax
call. Whenever the there is an Ajax call within the scope where ‘$.ajaxSetup({…. });
‘ is specified, [i.e., if ajaxsetup
is specified globally to the entire application, then it binds headers
property to all Ajax calls throughout the application].
Step 4: Create a Custom Validation Filter
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateCustomAntiForgeryTokenAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext != null && filterContext.HttpContext != null &&
filterContext.HttpContext.Request != null &&
!string.IsNullOrEmpty(filterContext.HttpContext.Request.HttpMethod)
&& string.Compare(filterContext.HttpContext.Request.HttpMethod, "POST", true) == 0)
{
ValidateRequestHeader(filterContext.HttpContext.Request);
}
}
private void ValidateRequestHeader(HttpRequestBase request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders = request.Headers.GetValues("RequestVerificationToken");
if (tokenHeaders != null && tokenHeaders.Count() > 0)
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
}
}
}
Create ValidateCustomAntiForgeryTokenAttribute
filter and register in FilterConfig
as filters.Add(new ValidateCustomAntiForgeryTokenAttribute());
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new ValidateCustomAntiForgeryTokenAttribute());
}
}
This class is available inside App_Start folder in the MVC Project.
Step 5: Assign Filter to the Action Method Called in Ajax Post
[HttpPost]
[ValidateCustomAntiForgeryToken]
public JsonResult IndexSingle(string data)
{
return Json(data, JsonRequestBehavior.AllowGet);
}
Here, the filter checks before the control hits the action and validates the token proceed if token is valid, otherwise control will not go to the corresponding method.
Control Flow
- Request from the Ajax call
$.ajax({});
- Hits the filter if it is a valid Ajax call.
Control goes to:
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext != null && filterContext.HttpContext != null &&
filterContext.HttpContext.Request != null &&
!string.IsNullOrEmpty(filterContext.HttpContext.Request.HttpMethod)
&& string.Compare(filterContext.HttpContext.Request.HttpMethod, "POST", true) == 0)
{
ValidateRequestHeader(filterContext.HttpContext.Request);
}
}
- In
If()
condition, it checks the request to the server is Ajax post request or not if the condition is true
, then it calls ValidateRequestHeader(filterConte…….);
method with the request as parameter.
private void ValidateRequestHeader(HttpRequestBase request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders = request.Headers.GetValues("RequestVerificationToken");
if (tokenHeaders != null && tokenHeaders.Count() > 0)
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
}
}
- In this method, it separates the token from the headers with property name
["RequestVerificationToken"]
specified in the $.ajaxSetup({})
.
- Split the token value to get the
cookieToken
and formToken
which is separated by ‘:
’
- Validate the token as
System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);
If valid, the control proceeds to the action method called through $.ajax
.