0

This delete button will only call the controller method if I remove the ValidateAntiForgeryToken attribute. How can I change either of these methods to keep the antiforgery token. I am assuming .NET does not believe this way of deleting is safe and causes the AJAX to not hit the controller. I would like to find the most secure way possible to send a delete call.

Delete button AJAX.

$("table").on("click", ".btn-delete", function (e) {
            var thisId = $(this).data('id');
            if (confirm("Are you sure you want to delete this item?")) {
                $.post('/AdminPortal/Client/Delete/', { id: thisId }, function (data) {
                    window.location.href = "/AdminPortal/Client/Index";
                });
            }
        });

Delete Method Controller

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(string id)
{
    //add priv check here in the future
    var client = baseSvc.ClientRepo.GetById(long.Parse(id));
    if (client != null)
    {
        client.IsActive = false;
        baseSvc.ClientRepo.Save(client);
    }
    return RedirectToAction(nameof(Index), new { area = nameof(AdminPortal) });
 }
RobertDev22
  • 119
  • 7

2 Answers2

1

What I have in my code for this is the following:

global JavaScript function

// CSRF (XSRF) security
function addAntiForgeryToken(data) {
    //if the object is undefined, create a new one.
    if (!data) {
        data = {};
    }
    //add token
    var tokenInput = $('input[name=__RequestVerificationToken]');
    if (tokenInput.length) {
        data.__RequestVerificationToken = tokenInput.val();
    }
    return data;
};

in my _Layout.cshtml (somewhere so it is on every page)

@Html.AntiForgeryToken()

usage: Then before doing your POST you can call the method to add a token to your data:

let data = addAntiForgeryToken({ id: thisId });
$.post('/AdminPortal/Client/Delete/', data, function (response) {
    window.location.href = "/AdminPortal/Client/Index";
});
lordvlad30
  • 391
  • 1
  • 17
1

I've lost hours trying to fix this problem in .NET 7. There are many solutions, but for versions prior to .NET 6, they are no longer functional. The only solution that actually worked—and it's actually very simple—was to set the name of the anti-forgery header, on the server side, and then set it on the client side via post headers:

  1. On the server side, include the following:

    builder.Services.AddAntiforgery(x => x.HeaderName = "X-ANTI-FORGERY-TOKEN");
    

    Optionally, add the auto validation, or manually add the decorator on the controller methods:

    builder.Services.AddControllersWithViews(options =>
    {               
        options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
    })
    
  2. On the client side, add the following:

    @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
    {
        @Html.AntiForgeryToken()
    }
    
  3. In the post method (Axios, jQuery, etc), get the element value and then assign it to a header. I'm using Axios:

    let tokenInput = document.querySelector('input[name=__RequestVerificationToken]');
    
    let token = tokenInput.value;
    
    let customConfig = {
        headers: {
            'Content-Type': 'application/json',
            'X-ANTI-FORGERY-TOKEN': token //note the same name given before
        }
    };
    
    axios.post(url, data, customConfig).then....//whatever
    
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
paulodrjr
  • 41
  • 4