Cloud

ASP.NET MVC anti-forgery token demystified – part 3: AJAX

AJAX This blog post is third and final in series about MVC anti-forgery (CSRF) token.
Part 1.
Part 2.As we talked about it earlier, MVC have a great built-in functionality for securing form posts with anti-forgery tokens and it’s even possible make it work across multiple web applications.

However, these days modern web applications tend to have more asynchronous (AJAX) communication between browser and web server   than traditional HTML form posts where the whole page is reloaded. The question is, can built-in MVC components to be used for CSRF validation when browser code is using AJAX to post to the server?
Obviously, it can’t be used directly because @Html.AntiForgeryToken only works when it’s placed inside HTML form and that form is submitted to the server. In case of AJAX post there is no form, so the AJAX controller method will not receive a form CSRF token (cookie token though will flow with the AJAX post normally).  However,  we can make it work with a little of extra coding…

The simplest way to solve this issue is to create an empty HTML form (which is serve only as a placeholder), place anti-forgery token on it and then extract the token value with javascript and add it to AJAX post payload. From may look something like that:

<form id="_CRSFform" action="#" method="post"><%= Html.AntiForgeryToken()%></form>  
Microsoft - The Essential Guide to Microsoft Teams End-User Engagement
The Essential Guide to Microsoft Teams End-User Engagement

We take you through 10 best practices, considerations, and suggestions that can enrich your Microsoft Teams deployment and ensure both end-user adoption and engagement.

Get the Guide

And then have the following javascript (utilizing jQuery) code to extract the token and add it to AJAX post payload:

AddAntiForgeryToken = function(data) {
    data.__RequestVerificationToken = $('#_CRSFform input[name=__RequestVerificationToken]').val(); return data; };

After that it’s very easy to add anti-forgery token to every post:

$.ajax({
    type: "post",
    dataType: "html",
    url: "/profile/edit",
    data: AddAntiForgeryToken(myPayload),
    success: function (response) {
        // ....
    }
});

This approach,  however, is not ideal. First, it requires you to add this pseudo-form to each of your pages and then you need to call a javascript function to add CSRF token to every ajax post. Also, you modifying your post body by adding the token, which is not very optimal either.
The more comprehensive, although more coding intensive approach would be to create your own anti-forgery token helpers and validators (which still be utilizing MVC’s AntiForgery class internally).
I’m not going to include the full source code to this post, just want to stop by on a few key moments:
1. Create your own HtmlHelper extension which would be generating HTML form input element with anti-forgery token when it’s used inside a HTML form or a javascript when used outside of the form (javascript will install a jQuery AJAX hook which will be adding anti-forgery token to every AJAX post):
if (typeof jQuery != ‘undefined’ && typeof _CSRFPrefilter == ‘undefined’) {
_ACE_CSRFPrefilter = function (options, originalOptions, jqXHR) {
var verificationToken = $(“input[name=’__MyRequestVerificationToken’]”).attr(‘value’);
if (verificationToken) {
jqXHR.setRequestHeader(“X-Request-Verification-Token”, verificationToken);
}
}
$.ajaxPrefilter(_CSRFPrefilter);
}
2. Create your own controller action filter for verifying anti-forgery token:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class MyValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
which will try to get a anti-forgery token from the post header (AJAX) or from the post body (HTML form):
string formValue = filterContext.HttpContext.Request.Headers[AntiForgeryData.GetAntiForgeryTokenHeaderName()];
if (String.IsNullOrEmpty(formValue))
{
formValue = filterContext.HttpContext.Request.Form[AntiForgeryData.GetAntiForgeryTokenName(null)];
After that, you’ll be able to use your new Html helper to either generate a token inside HTML form or simply call it anywhere on the page to register a script helper for AJAX. AJAX post code will not need any additional modifications at all, the jQuery AJAX prefilter will take care of adding anti-forgery token to every post.

About the Author

Solutions Architect at Perficient

More from this Author

Thoughts on “ASP.NET MVC anti-forgery token demystified – part 3: AJAX”

  1. Thank you for the great articles on CSRF. I am looking for a solution to handle CSRF with ajax posts and would love to see how you implemented your solution. Any help would be greatly appreciated.

  2. Stan Tarnovskiy

    Thank you, Matthew!
    I’ll be glad to help you. You can see my implementation in the blog post above. Please let me know if you have any problems with that.

  3. Thanks for your great solution related to ajax post.
    Can you please share the code for it , so that it is easy to implement …

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to the Weekly Blog Digest:

Sign Up