Search code examples
.netasp.netasp.net-mvc-3csrf

How to handle CSRF attacks when using ajax post?


I basically want to make an ajax post to send some stateId and get back some list of cities from that state.

<form id="frmAjax" action="#">
    @Html.DropDownList("states", (SelectList)ViewBag.States)
    @Html.AntiForgeryToken()
</form>

I do the request like this:

function PopulateTable() {
        var x=$("#frmAjax").serialize();
        $.ajax({
            url: '@Url.Action("GetCities")',
            type: 'POST',
            dataType: 'json',
            data: [1]
            success: function (data) {
                var target = $(".displayData tbody");
                target.empty();
                for (var i = 0; i < data.length; i++) {
                    target.append('<tr><td>' + data[i].Id + '</td><td>' + data[i].Name + '</td><td>' + data[i].Population+ '</td></tr>');
                }
            }
        });
    }

The action is something like this

    [ValidateAntiForgeryToken]
    public JsonResult GetCities([2])
    {
        var cities= new Service().GetCities(stateId);
        return Json(classes);
    }

What should i put instead of [1] and [2] so it can work? I basically want this ajax post to be as secure as a regular post with AntiForgeryToken() and ValidateAntiForgeryToken. Thanks.


Solution

  • You were almost there:

    function PopulateTable() {
        $.ajax({
            url: '@Url.Action("GetCities")',
            type: 'POST',
            dataType: 'json',
            data: $("#frmAjax").serialize(),
            success: function (data) {
                var target = $(".displayData tbody");
                target.empty();
                for (var i = 0; i < data.length; i++) {
                    target.append('<tr><td>' + data[i].Id + '</td><td>' + data[i].Name + '</td><td>' + data[i].Population+ '</td></tr>');
                }
            }
        });
    }
    

    and then:

    [ValidateAntiForgeryToken]
    [HttpPost]
    public JsonResult GetCities(int stateId)
    {
        var cities = new Service().GetCities(stateId);
        return Json(cities);
    }
    

    this obviously supposes that you use a view model (which by the way you should always use) and:

    @Html.DropDownListFor(x => x.StateId, Model.States)
    

    or if you don't want to use view models (against my recommendation) make sure you provide a proper name to this weakly typed helper:

    @Html.DropDownList("stateId", (SelectList)ViewBag.States)