215

I have implemented in my app the mitigation to CSRF attacks following the informations that I have read on some blog post around the internet. In particular these post have been the driver of my implementation

Basically those articles and recommendations says that to prevent the CSRF attack anybody should implement the following code:

  1. Add the [ValidateAntiForgeryToken] on every action that accept the POST Http verb

    [HttpPost] [ValidateAntiForgeryToken] public ActionResult SomeAction( SomeModel model ) { }

  2. Add the <%= Html.AntiForgeryToken() %> helper inside forms that submits data to the server

Anyway in some parts of my app I am doing Ajax POSTs with jQuery to the server without having any form at all. This happens for example where I am letting the user to click on an image to do a specific action.

Suppose I have a table with a list of activities. I have an image on a column of the table that says "Mark activity as completed" and when the user click on that activity I am doing the Ajax POST as in the following sample:

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {},
        success: function (response) {
            // ....
        }
    });
});

How can I use the <%= Html.AntiForgeryToken() %> in these cases? Should I include the helper call inside the data parameter of the Ajax call?

Sorry for the long post and thanks very much for helping out

EDIT:

As per jayrdub answer I have used in the following way

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {
            AddAntiForgeryToken({}),
            id: parseInt($(this).attr("title"))
        },
        success: function (response) {
            // ....
        }
    });
});
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Lorenzo
  • 29,081
  • 49
  • 125
  • 222
  • The [David Hayden link](http://davidhayden.com/blog/dave/archive/2009/04/29/AntiForgeryTokenInMVCFramework.aspx) now 404s, it appears that he's migrated his blog to a new CMS, but didn't migrate all the old content over. –  Jan 02 '13 at 17:20

21 Answers21

261

I use a simple js function like this

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

Since every form on a page will have the same value for the token, just put something like this in your top-most master page

<%-- used for ajax in AddAntiForgeryToken() --%>
<form id="__AjaxAntiForgeryForm" action="#" method="post"><%= Html.AntiForgeryToken()%></form>  

Then in your ajax call do (edited to match your second example)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});
JeremyWeir
  • 24,118
  • 10
  • 92
  • 107
  • 6
    Nice, I like the encapsulation of the token fetching. – jball Nov 02 '10 at 01:18
  • Yeah, that's nice since a lot of times you do ajax posts you don't even have a form on the page to get the token from – JeremyWeir Nov 02 '10 at 01:21
  • @jayrdub: thanks for your response! Where do I have to place the small js function? I have placed inside a js file of common function and either in the master page but Chrome give me an error when I use it. It says `Unexpected token (`. Please see my question edit to see how I am using it. – Lorenzo Nov 02 '10 at 01:50
  • 2
    @Lorenzo, put your custom data inside the call to `AddAntiForgeryToken`, like so: `data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),` – jball Nov 02 '10 at 02:15
  • jay, nice one. useful generic implementation. been working on the edges of something (less nice) for quite some time. – jim tollan Apr 10 '11 at 12:45
  • @JeremyWeir What's the purpose of passing the `id` to the `AddAntiForgeryToken()` – painotpi Feb 27 '13 at 09:58
  • That's just an example of how to merge the antiforgery token into whatever data object you want to send. Nothing special about it, it just matches the OP's example. – JeremyWeir Feb 27 '13 at 18:09
  • Re the above comment, when I implemented it, my url already had parameters in it (e.g. /action/id=444), so I simply didn't pass anything to AddAntiForgeryToken({}) , and it worked fine for me. – James in Indy May 21 '13 at 17:28
  • 3
    How bad an idea would it be to use [`ajaxSend`](http://api.jquery.com/ajaxSend/) or override [`ajax`](http://stackoverflow.com/questions/4536788/override-jquery-functions) to always augment `data` with the anti-forgery token? Maybe adding some check to make sure that the `url` is destined for your server. – ta.speot.is Jul 04 '13 at 06:14
  • 1
    Be careful if you use output cache. – Barbaros Alp Nov 02 '14 at 18:36
  • what happens when i make a second ajax request on the same page without reloading? wouldn't the token be invalid then? – Souhaieb Besbes Dec 28 '15 at 09:08
  • 2
    @SouhaiebBesbes the validation token should be the same for a user across all pages (it works in conjunction with a cookie that is set and stays the same). So it doesn't matter if there are multiple requests per page, it'll be the same if the base page reloaded anyway. – JeremyWeir Dec 28 '15 at 10:58
  • @JeremyWeir thanks, it turns i misunderstood how those tokens work – Souhaieb Besbes Dec 28 '15 at 11:07
  • this will not work with outputcache enabled on your page – sqlnewbie Feb 04 '16 at 19:16
  • @sqlnewbie true, depending on the outputcache configuration. Caching the same output for different users is definitely a common usage, but it is possible to have the outputcache keyed on the same user. – JeremyWeir Feb 05 '16 at 20:56
  • @JeremyWeir Is the form required or can you just do: @Html.AntiForgeryToken() on the page? In my case my page only lists a bunch of products in a grid, but I am doing the deleting with an AJAX request so need the token, but don't want to add an empty form to my page if not necessary. – Blake Rivell Apr 17 '16 at 23:04
  • 1
    @BlakeRivell I doubt it is required for it to work, the form is there to keep the html valid. – JeremyWeir Apr 18 '16 at 23:36
  • Why isn't it added to the header instead? Is there a preferable way? – Murphybro2 Nov 22 '17 at 11:11
32

I like the solution provided by 360Airwalk, but it may be improved a bit.

The first problem is that if you make $.post() with empty data, jQuery doesn't add a Content-Type header, and in this case ASP.NET MVC fails to receive and check the token. So you have to ensure the header is always there.

Another improvement is support of all HTTP verbs with content: POST, PUT, DELETE etc. Though you may use only POSTs in your application, it's better to have a generic solution and verify that all data you receive with any verb has an anti-forgery token.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content
            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
            // ensure Content-Type header is present!
            if (opt.contentType !== false || event.contentType) {
                request.setRequestHeader( "Content-Type", opt.contentType);
            }
        }
    });
});
Bronx
  • 747
  • 8
  • 12
  • 1
    +1 you are right, i've not thought of the empty post call issue. thanks for the input. you were right about that we do not use delete/put yet in our project. – 360Airwalk Sep 19 '12 at 15:37
  • 2
    +1 for saving me from having to add the function to all the jQuery.Ajax calls – Dragos Durlut Oct 09 '12 at 07:40
  • 2
    +1 Just as a note for posterity, the jQuery documentation for `.ajaxSend()` states "As of jQuery 1.8, the .ajaxSend() method should only be attached to document." http://api.jquery.com/ajaxsend/ – RJ Cuthbertson Aug 28 '14 at 19:22
  • 1
    @Bronx Where does the `options` come from, which is listed in the final `if` statement? Thanks. – hvaughan3 Apr 20 '16 at 16:19
  • Beware using this if you have multiple forms on a page. You will need to set the value in beforeSend with a more specific selector call instead of for the document. – Dan Sep 11 '16 at 05:27
  • I'm unsure why this is so complex, why can it not just set the token and be done with 1 line of code as done here (if we remove the if condition for "POST") - https://erlend.oftedal.no/blog/static-118.html?blogid=118 – PandaWood May 09 '19 at 08:09
  • @PandaWood My main points were that 1) it is not enough to cover POST requests only, you should do the same for all requests having any content, and 2) if you resort to the hidden field method, you *must* include a `Content-Type` header. – Bronx May 11 '19 at 01:40
  • @PandaWood, my answer was a modification of another answer which used a hidden form field to pass the token, hence the complexities. This method does not require changes on the server because ASP.NET MVC supports the hidden form field out-of-the-box. One can also use a header like `X-CSRF-Token`, but it will require a token validation code on a server as described in https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks. So it is up to you to decide. There is already another answer in the topic suggesting to use a header instead. – Bronx May 11 '19 at 02:11
  • Thanks @Bronx yes I failed to understand that ASP.NET doesn't read from the header (by default) and so this is necessary to cater for what the `ValidateAntiForgeryTokenAttribute` does – PandaWood May 12 '19 at 06:38
  • @Bronx what about forms with formData and processData/contentType set to false? – Angelo Jun 23 '20 at 15:37
  • Never mind, the issue was appending the actual token. I used `if (opt.data instanceof FormData) { opt.data.append("__RequestVerificationToken", securityToken); } else...` – Angelo Jun 24 '20 at 08:25
25

I know there are a lot of other answers, but this article is nice and concise and forces you to check all of your HttpPosts, not just some of them:

http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

It uses HTTP headers instead of trying to modify the form collection.

Server

//make sure to add this to your global action filters
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value 
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Client

var token = $('[name=__RequestVerificationToken]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;

$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: headers,
    contentType: 'application/json; charset=utf-8',
    data: { title: "This is my title", contents: "These are my contents" },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});
viggity
  • 15,039
  • 7
  • 88
  • 96
  • 5
    The attribute from the article you linked too combined with [Bronx's response](http://stackoverflow.com/a/12116344/550073) is the ultimate DRY solution to this problem. – TugboatCaptain Apr 02 '14 at 00:47
  • 2
    Great find. I edited your answer to include the code snippets so the answer stands on its own, but I hope people will read the rest of the article as well. This appears to be a very clean solution. – Tim M. Apr 17 '14 at 21:24
  • thanks Tim, it is an excellent idea, its frustrating when a link goes dead and the answer becomes worthless. I've started doing this on all my new answers. – viggity Jul 29 '14 at 13:58
  • Is this MVC, WebAPI or .NetCore ? I can't get the correct namespaces for WebAPI 5 – Myster Dec 19 '19 at 21:54
  • It's also worth checking PATCH and PUT verbs. If you're using those. – Drew Delano Dec 02 '21 at 03:54
23

I feel like an advanced necromancer here, but this is still an issue 4 years later in MVC5.

To handle ajax requests properly the anti-forgery token needs to be passed to the server on ajax calls. Integrating it into your post data and models is messy and unnecessary. Adding the token as a custom header is clean and reusable - and you can configure it so you don't have to remember to do it every time.

There is an exception - Unobtrusive ajax does not need special treatment for ajax calls. The token is passed as usual in the regular hidden input field. Exactly the same as a regular POST.

_Layout.cshtml

In _layout.cshtml I have this JavaScript block. It doesn't write the token into the DOM, rather it uses jQuery to extract it from the hidden input literal that the MVC Helper generates. The Magic string that is the header name is defined as a constant in the attribute class.

<script type="text/javascript">
    $(document).ready(function () {
        var isAbsoluteURI = new RegExp('^(?:[a-z]+:)?//', 'i');
        //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative

        $.ajaxSetup({
            beforeSend: function (xhr) {
                if (!isAbsoluteURI.test(this.url)) {
                    //only add header to relative URLs
                    xhr.setRequestHeader(
                       '@.ValidateAntiForgeryTokenOnAllPosts.HTTP_HEADER_NAME', 
                       $('@Html.AntiForgeryToken()').val()
                    );
                }
            }
        });
    });
</script>

Note the use of single quotes in the beforeSend function - the input element that is rendered uses double quotes that would break the JavaScript literal.

Client JavaScript

When this executes the beforeSend function above is called and the AntiForgeryToken is automatically added to the request headers.

$.ajax({
  type: "POST",
  url: "CSRFProtectedMethod",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  success: function (data) {
    //victory
  }
});

Server Library

A custom attribute is required to process the non standard token. This builds on @viggity's solution, but handles unobtrusive ajax correctly. This code can be tucked away in your common library

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public const string HTTP_HEADER_NAME = "x-RequestVerificationToken";

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {

            var headerTokenValue = request.Headers[HTTP_HEADER_NAME];

            // Ajax POSTs using jquery have a header set that defines the token.
            // However using unobtrusive ajax the token is still submitted normally in the form.
            // if the header is present then use it, else fall back to processing the form like normal
            if (headerTokenValue != null)
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, headerTokenValue);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Server / Controller

Now you just apply the attribute to your Action. Even better you can apply the attribute to your controller and all requests will be validated.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}
Will D
  • 844
  • 10
  • 12
  • Perfect solution, much more centralized. Thanks – David Freire Apr 02 '15 at 13:32
  • Can you explain in more detail why you only want to add the header for relative URLs? That went over my head. Great solution! – MattM Sep 01 '15 at 17:30
  • relative ensures that the header is only set on requests going back to your own server, as the ajax setup covers all requests made with jquery, we don't want the token being sent on jsonp or CORS requets. This maybe true for absolute urls too, but relative are guaranteed to be same domain. – Will D Sep 02 '15 at 03:16
  • 1
    @WillD I liked your solution, but was forced to modify it a bit. Because you choose `$.ajaxSetup` to define a general `beforesend` eventhandler it can happen that you overwrite it. I found [another solution](http://stackoverflow.com/a/24166395/97017) where you can add a second handler which will also be called. Works nicely and doesn't break your implementation. – Viper Dec 02 '15 at 21:54
  • Does anyone have an ASP.net 5 version of the customer validate AntiForgery attribute? This version does not compile in the latest version! – Rob Jan 15 '16 at 00:44
  • I get an error in the JS - "." is not valid at the start of a code block. Only identifiers, keywords, comments, "(" and "{" are valid. – Spencer Sullivan Nov 15 '19 at 15:57
20

Don't use Html.AntiForgeryToken. Instead, use AntiForgery.GetTokens and AntiForgery.Validate from Web API as described in Preventing Cross-Site Request Forgery (CSRF) Attacks in ASP.NET MVC Application.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
  • For controller action methods that model bind a server model type to the posted AJAX JSON, having the content type as "application/json" is required for the proper model binder to be used. Unfortunately, this precludes using form data, required by the [ValidateAntiForgeryToken] attribute, so your method is the only way I could find to make it work. My only question is, does it still work in a web farm or multiple Azure web role instances? Do you @Edward, or anyone else know if this is a problem? – Richard B May 15 '13 at 22:27
  • @Edward Brey Can you please elaborate on why we shouldn't use it? – Odys Feb 11 '14 at 22:43
  • 4
    @Odys: There's nothing inherently wrong with Html.AntiForgeryToken, but it has downsides: requires a form, requires jQuery, and assumes undocumented Html.AntiForgeryToken implementation details. Still, it's fine in many contexts. My statement "Don't use Html.AntiForgeryToken" probably comes off too strong. My meaning is that it's not intended to be used with Web API, whereas the more flexible AntiForgery.GetTokens is. – Edward Brey Feb 11 '14 at 22:59
  • thx! I had to change it a bit to make it work for an MVC5 controller, but this was the solution – jao Aug 25 '14 at 08:15
  • 3
    It certainly does not require a form. You just need to parse the DOM for it by name. Using jquery, I can add it inside my data object via data { __RequestVerificationToken: $("input[name=__RequestVerificationToken]").val() } – Anthony Mason May 06 '16 at 13:37
  • This answer provides no reasoning for a bold assertion and the main point refers to a dead link. As it turns out, I do need to use AntiForgery methods, because I want to put the token into the header where I think it should be, but where ASP.NET doesn't look - when using its `ValidateAntiForgeryToken` attribute – PandaWood May 13 '19 at 01:59
  • @PandaWood I updated the link to the new doc location. – Edward Brey May 14 '19 at 13:20
19

I think all you have to do is ensure that the "__RequestVerificationToken" input is included in the POST request. The other half of the information (i.e. the token in the user's cookie) is already sent automatically with an AJAX POST request.

E.g.,

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: { 
            "__RequestVerificationToken":
            $("input[name=__RequestVerificationToken]").val() 
        },
        success: function (response) {
            // ....
        }
    });
});
jball
  • 24,791
  • 9
  • 70
  • 92
  • 1
    After many hours experimenting with jQuery AJAX posting from within an MVC (Razor) page this was the simplest answer of all that worked for me. Just include your own data fields (or the viewModel I suppose) after the token as a new piece of data (but within the original data object). – Ralph Bacon Sep 07 '13 at 13:29
  • How would I implement this if the AJAX function was in a .html page and not a Razor page? – Bob the Builder Aug 13 '14 at 10:29
  • If your html page doesn't have a server supplied `AntiForgeryToken` it's all moot anyhow. If it does (not sure how you're getting one in that case, but assuming you are), then the above would work just fine. If you're attempting to create a simply webpage that will post a request to a server expecting said token, and the server did not generate said page, then you're out of luck. That's essentially the point of the AntiForgeryToken... – jball Aug 13 '14 at 20:22
16

I was just implementing this actual problem in my current project. i did it for all ajax-POSTs that needed an authenticated user.

First off i decided to hook my jquery ajax calls so i do not to repeat myself too often. this javascript snippet ensures all ajax (post) calls will add my request validation token to the request. Note: the name __RequestVerificationToken is used by the .Net framework so i can utilize the standard Anti-CSRF features as shown below.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

In your Views where you need the token to be available to the above javascript just use the common HTML-Helper. You can basically add this code whereever you want. I placed it within a if(Request.IsAuthenticated) statement:

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

In your controller simply use the standard ASP.Net MVC Anti-CSRF mechanism. I did it like this (though i actually used Salt).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

With Firebug or a similar tool you can easily see how your POST requests now have a __RequestVerificationToken parameter appended.

Kobi
  • 135,331
  • 41
  • 252
  • 292
360Airwalk
  • 2,189
  • 1
  • 16
  • 13
8

You can do this also:

$("a.markAsDone").click(function (event) {
    event.preventDefault();

    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: $('<form>@Html.AntiForgeryToken()</form>').serialize(),
        success: function (response) {
        // ....
        }
    });
});

This is using Razor, but if you're using WebForms syntax you can just as well use <%= %> tags

Aran Mulholland
  • 23,555
  • 29
  • 141
  • 228
4

Further to my comment against @JBall's answer that helped me along the way, this is the final answer that works for me. I'm using MVC and Razor and I'm submitting a form using jQuery AJAX so I can update a partial view with some new results and I didn't want to do a complete postback (and page flicker).

Add the @Html.AntiForgeryToken() inside the form as usual.

My AJAX submission button code (i.e. an onclick event) is:

//User clicks the SUBMIT button
$("#btnSubmit").click(function (event) {

//prevent this button submitting the form as we will do that via AJAX
event.preventDefault();

//Validate the form first
if (!$('#searchForm').validate().form()) {
    alert("Please correct the errors");
    return false;
}

//Get the entire form's data - including the antiforgerytoken
var allFormData = $("#searchForm").serialize();

// The actual POST can now take place with a validated form
$.ajax({
    type: "POST",
    async: false,
    url: "/Home/SearchAjax",
    data: allFormData,
    dataType: "html",
    success: function (data) {
        $('#gridView').html(data);
        $('#TestGrid').jqGrid('setGridParam', { url: '@Url.Action("GetDetails", "Home", Model)', datatype: "json", page: 1 }).trigger('reloadGrid');
    }
});

I've left the "success" action in as it shows how the partial view is being updated that contains an MvcJqGrid and how it's being refreshed (very powerful jqGrid grid and this is a brilliant MVC wrapper for it).

My controller method looks like this:

    //Ajax SUBMIT method
    [ValidateAntiForgeryToken]
    public ActionResult SearchAjax(EstateOutlet_D model) 
    {
        return View("_Grid", model);
    }

I have to admit to not being a fan of POSTing an entire form's data as a Model but if you need to do it then this is one way that works. MVC just makes the data binding too easy so rather than subitting 16 individual values (or a weakly-typed FormCollection) this is OK, I guess. If you know better please let me know as I want to produce robust MVC C# code.

Ralph Bacon
  • 123
  • 1
  • 6
4

found this very clever idea from https://gist.github.com/scottrippey/3428114 for every $.ajax calls it modifies the request and add the token.

// Setup CSRF safety for AJAX:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:
        if (options.contentType.indexOf('application/json') === 0) {
            // Add the token to the URL, because we can't add it to the JSON data:
            options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();
        } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {
            // Append to the data string:
            options.data += (options.data ? "&" : "") + token.serialize();
        }
    }
});
masterlopau
  • 563
  • 1
  • 4
  • 13
  • I tried several of the other alternatives above, this is what solved it for me. – HostMyBus Apr 25 '19 at 02:13
  • I did however have to add `if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {` to catch Ajax calls that had not specified a content type – HostMyBus Apr 25 '19 at 02:23
3

1.Define Function to get Token from server

@function
{

        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
}

2.Get token and set header before send to server

var token = '@TokenHeaderValue()';    

       $http({
           method: "POST",
           url: './MainBackend/MessageDelete',
           data: dataSend,
           headers: {
               'RequestVerificationToken': token
           }
       }).success(function (data) {
           alert(data)
       });

3. Onserver Validation on HttpRequestBase on method you handle Post/get

        string cookieToken = "";
        string formToken = "";
        string[] tokens = Request.Headers["RequestVerificationToken"].Split(':');
            if (tokens.Length == 2)
            {
                cookieToken = tokens[0].Trim();
                formToken = tokens[1].Trim();
            }
        AntiForgery.Validate(cookieToken, formToken);
Mohammad Olfatmiri
  • 1,605
  • 5
  • 31
  • 57
3

first use @Html.AntiForgeryToken() in html

 $.ajax({
        url: "@Url.Action("SomeMethod", "SomeController")",
        type: 'POST',
        data: JSON.stringify(jsonObject),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: false,
        beforeSend: function (request) {
            request.setRequestHeader("RequestVerificationToken", $("[name='__RequestVerificationToken']").val());
        },
        success: function (msg) {
            alert(msg);
        }
Amir Reza
  • 435
  • 1
  • 7
  • 15
1

Here is the easiest way I've seen. Note: Make sure you have "@Html.AntiForgeryToken()" in your View

  $("a.markAsDone").click(function (event) {
        event.preventDefault();
        var sToken = document.getElementsByName("__RequestVerificationToken")[0].value;
        $.ajax({
            url: $(this).attr("rel"),
            type: "POST",
            contentType: "application/x-www-form-urlencoded",
            data: { '__RequestVerificationToken': sToken, 'id': parseInt($(this).attr("title")) }
        })
        .done(function (data) {
            //Process MVC Data here
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            //Process Failure here
        });
    });
1

I aware it's been some time since this question was posted, but I found really useful resource, which discusses usage of AntiForgeryToken and makes it less troublesome to use. It also provides jquery plugin for easily including antiforgery token in AJAX calls:

Anti-Forgery Request Recipes For ASP.NET MVC And AJAX

I'm not contributing much, but maybe someone will find it useful.

slawek
  • 2,709
  • 1
  • 25
  • 29
  • That post is like a mile long! I'm sure it's great but tl;dr – BritishDeveloper Apr 27 '12 at 14:25
  • 1
    Too bad, because it nicely covers subject. It not only tells you how to use the feature, but explains what problem it fixes and give you context to understand how to use it correctly. When it comes to security I think in-depth understanding is important. – slawek Apr 27 '12 at 17:34
  • 2
    If it's important it should be written in a way that encourages people to read it ;) – BritishDeveloper Apr 30 '12 at 08:26
0

Slight improvement to 360Airwalk solution. This imbeds the Anti Forgery Token within the javascript function, so @Html.AntiForgeryToken() no longer needs to be included on every view.

$(document).ready(function () {
    var securityToken = $('@Html.AntiForgeryToken()').attr('value');
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});
Barry MSIH
  • 3,525
  • 5
  • 32
  • 53
0
function DeletePersonel(id) {

    var data = new FormData();
    data.append("__RequestVerificationToken", "@HtmlHelper.GetAntiForgeryToken()");

    $.ajax({
        type: 'POST',
        url: '/Personel/Delete/' + id,
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function (result) {
        }
    });
}

public static class HtmlHelper {
    public static string GetAntiForgeryToken() {
        System.Text.RegularExpressions.Match value = 
                System.Text.RegularExpressions.Regex.Match(System.Web.Helpers.AntiForgery.GetHtml().ToString(), 
                        "(?:value=\")(.*)(?:\")");
        if (value.Success) {
            return value.Groups[1].Value;
        }
        return "";
    }
}
DimaSan
  • 12,264
  • 11
  • 65
  • 75
ismail eski
  • 81
  • 1
  • 5
0

I'm using a ajax post to run a delete method (happens to be from a visjs timeline but that's not relelvant). This is what I sis:

This is my Index.cshtml

@Scripts.Render("~/bundles/schedule")
@Styles.Render("~/bundles/visjs")
@Html.AntiForgeryToken()

<!-- div to attach schedule to -->
<div id='schedule'></div>

<!-- div to attach popups to -->
<div id='dialog-popup'></div>

All I added here was @Html.AntiForgeryToken() to make the token appear in the page

Then in my ajax post I used:

$.ajax(
    {
        type: 'POST',
        url: '/ScheduleWorks/Delete/' + item.id,
        data: {
            '__RequestVerificationToken': 
            $("input[name='__RequestVerificationToken']").val()
              }
     }
);

Which adds the token value, scraped off the page, to the fields posted

Before this I tried putting the value in the headers but I got the same error

Feel free to post improvements. This certainly seems to be a simple approach that I can understand

Nick.Mc
  • 18,304
  • 6
  • 61
  • 91
0

Okay lots of posts here, none of them helped me, days and days of google, and still no further I got to the point the wr-writing the whole app from scratch, and then I noticed this little nugget in my Web.confg

 <httpCookies requireSSL="false" domain="*.localLookup.net"/>

Now I don't know why I added it however I have since noticed, its ignored in debug mode and not in a production mode (IE Installed to IIS Somewhere)

For me the solution was one of 2 options, since I don't remember why I added it I cant be sure other things don't depend on it, and second the domain name must be all lower case and a TLD not like ive done in *.localLookup.net

Maybe it helps maybe it don't. I hope it does help someone

0

The Solution i found is not for ASPX but for Razor, but quite comperable issue.

I resolved it by adding the AntiForgery to the request. The HTML Helper does not create a HTML id with the call

@Html.AntiForgeryToken()

In order to add the token to the postrequest i just added the AntiForgery id to the hidden field with jquery:

$("input[name*='__RequestVerificationToken']").attr('id', '__AjaxAntiForgeryForm');

This caused the controller to accept the request with the [ValidateAntiForgeryToken] attribute

Dominik Sand
  • 462
  • 4
  • 7
0

Most of the answers above are for MVC applications. Yes, you need to add @Html.AntiForgeryToken() on your cshtml file and also get the security token in the js file and use it on you ajax post's data object.

However on the c# side, just a reminder, if you are using Razor pages, note that you cannot use [ValidateAntiForgeryToken] attribute on top of the methods. It will not give you an error but it will not have any effect since it only works on MVC apps. For razor pages, you need to use the attribute on top of the "model" class.

For example;

[ValidateAntiForgeryToken]
public class IndexModel : PageModel
{
     // rest of the class
}

This will apply the attribute to all the methods on the page.

Kara Kartal
  • 249
  • 1
  • 2
  • 8
-4

AntiforgeryToken is still a pain, none of the examples above worked word for word for me. Too many for's there. So I combined them all. Need a @Html.AntiforgeryToken in a form hanging around iirc

Solved as so:

function Forgizzle(eggs) {
    eggs.__RequestVerificationToken =  $($("input[name=__RequestVerificationToken]")[0]).val();
    return eggs;
}

$.ajax({
            url: url,
            type: 'post',
            data: Forgizzle({ id: id, sweets: milkway }),
});

When in doubt, add more $ signs

Hazza
  • 6,441
  • 3
  • 24
  • 37