I am currently developing an MVC application in ASP.net. I am using AJAX.ActionLink to provide a delete link in a list of records, however this is very insecure. I have put
To piggyback on the $.ajaxPrefilter
answers, I added the token to both options
and originalOptions
rather than the jqXHR
headers. This does require the token to be somewhere in a form on your page.
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
var token = $('input[name="__RequestVerificationToken"]');
if (token.length > 0) {
var data = options.data;
var dataArray = originalOptions.data;
if (data && !data.includes('__RequestVerificationToken')) {
options.data = data + '&__RequestVerificationToken=' + token.val();
}
if (dataArray && !('__RequestVerificationToken' in dataArray)) {
var tokenObject = { name: '__RequestVerificationToken', value: token.val() };
originalOptions.data.push(tokenObject);
}
}
});
Keep in mind that this will add this token to every single AJAX request on your page, so you may want to filter by the options.url
string or options.type == 'POST'
.
I don't know about the AJAX ActionLink specifically, but it is possible from a WebForms page to post to an MVC action with the [AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
attributes.
You can use reflection to get at the MVC methods used to set the cookie and matching form input used for the MVC validation.
See this answer: Using an MVC HtmlHelper from a WebForm
Use AntiForgeryToken with Ajax.ActionLink
In addition to jjwhite01 response;
to insert the token in Form data, use option.data
in Prefilter
$.ajaxPrefilter(
function (options, localOptions, jqXHR) {
if (options.type !== "GET") {
var token = GetAntiForgeryToken();
if (token !== null) {
if (options.data.indexOf("X-Requested-With") === -1) {
options.data = "X-Requested-With=XMLHttpRequest" + (options.data === "") ? "" : "&" + options.data;
}
options.data = options.data + "&" + token.name + '=' + token.value;
}
}
}
);
I haven't used any ajax helpers myself, but I don't see any reason why you cannot use a link. Personally I would use an onload event handler to unobtrusively create a link from the form itself, and then remove the form.
You can use AntiForgeryToken with Ajax.ActionLink but you need to manually insert the AntiForgeryToken into the header of your request like so:
function GetAntiForgeryToken(){
var tokenWindow = window;
var tokenName = "__RequestVerificationToken";
var tokenField = $(tokenWindow.document).find("input[type='hidden'][name='" + tokenName + "']");
if (tokenField.length == 0) {return null;}
else {
return {
name: tokenName,
value: tokenField.val()
};
}
};
Then, we can use $.ajaxPrefilter to insert it into the header:
$.ajaxPrefilter(
function (options, localOptions, jqXHR) {
var token = GetAntiForgeryToken();
jqXHR.setRequestHeader(token.name, token.value);
}
);
I wrote a post about it here. Hope this helps!
Have a look at this blog post.
Say you have an Action method like this:
[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken] public ActionResult DeleteAccount(int accountId) { // delete stuff }
And you call it via:
$.post('/home/DeleteAccount', { accountId: 1000 }, function() { alert('Account Deleted.'); });
Since the POST does not include the AntiForgeryToken, it will fail.
Fortunately, it doesn’t take much brainpower to fix this. All the client side component of AntiForgeryToken does is put the token in a basic hidden field. So, you just need to pull that data out and include it in your AJAX call.
var token = $('input[name=__RequestVerificationToken]').val();
$.post('/home/DeleteAccount', { accountId: 1000, '__RequestVerificationToken': token }, function() { alert('Account Deleted.'); });
Do note that if you have multiple forms on the page with multiple AntiForgeryTokens, you will have to specify which one you want in your jQuery selector. Another gotcha is if you are using jQuery’s
serializeArray()
function, you’ll have to add it a bit differently:
var formData = $('#myForm').serializeArray(); var token = $('input[name=__RequestVerificationToken]').val(); formData.push({ name: '__RequestVerificationToken', value: token });
$.post('/home/DeleteAccount', formData, function() { alert('Account Deleted.'); });
Update: The link has been fixed.