jQuery Ajax calls and the Html.AntiForgeryToken()

前端 未结 20 2385
鱼传尺愫
鱼传尺愫 2020-11-22 16:34

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

相关标签:
20条回答
  • 2020-11-22 17:11

    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 讨论(0)
  • 2020-11-22 17: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.

    0 讨论(0)
  • 2020-11-22 17:16

    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

    0 讨论(0)
  • 2020-11-22 17:18

    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

    0 讨论(0)
  • 2020-11-22 17:20

    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) {
                // ....
            }
        });
    });
    
    0 讨论(0)
  • 2020-11-22 17:20

    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.

    0 讨论(0)
提交回复
热议问题