6
votes

According to django documentation, for ajax post request in 1.3 (at least with Jquery), we just need to add this snippet to main js file. This snippet get csrftoken from cookies, and then set up it for all ajax request. That's work, but what if csrftoken don't exist in cookies? I thought render_to_response and render both automatically checks if csrftoken in sessions, and set it for us, if token not there. But they are not. So, i need to implement it by myself? Or maybe there is another way to handle ajax csrf protection?

5

5 Answers

11
votes

When there is no form on a page that is already using {% csrf_token %}, the cookie will not be sent. Therefore, as you noted, you will get an error when you attempt to use Ajax on such a page. This will lead to erratic behavior if you have a site with a mix of pages with various combinations of forms and ajax posts.

This has already been reported and fixed: https://code.djangoproject.com/ticket/15354

The solution in the patch, will should roll out with 1.3.1, is the ensure_cookie_csrf decorator. That decorator does not exist in 1.3 or 1.2.5

No need to wait, however. Just add this line to any view which contains AJAX posts a CSRF form:

request.META["CSRF_COOKIE_USED"] = True

Example:

def calculator(request):
    request.META["CSRF_COOKIE_USED"] = True
    return render_to_response('calc.html', {'form': CalcForm()})

FYI - this is exactly what that decorator does.

3
votes

Your cookie will only contain the CSRF token, if either the template tag {% csrf_token %} was used in the template to generate the request, or if you call get_token (with the request object as argument) from django.middleware.csrf.

The get_token function sets metainformation on the request object that in turn tells the django.middleware.csrf.CsrfViewMiddleware middleware to set the cookie.

3
votes

As for Ajax, you should pass the csrf token with every request. For jQuery, I use the following code:

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if(!options.crossDomain) {
        if(options.data) {
            options.data += "&";
        } else {
            options.data = "";
        }
        options.data += "csrfmiddlewaretoken={{csrf_token}}";
    }
});
1
votes

One way that I've found to get around this is by using a preexisting form as a starter point for your AJAX data.

<form id="ajax_form" stye="display: none;">{% csrf_token %}</form>

Then you can use this in your JavaScript via JQuery's Serialize function:

var data = $('#ajax_form').serialize();
data += "&mydata=69";

You can even use hidden fields within that hidden form so that you don't have to use string concatenation to built your POST data.

1
votes

If you are using the @csrf_protect decorator, make sure that both the view with the form and the view that the data is being posted to use the decorator.

I had a similar issue. I only had @csrf_protect on the post view which worked fine testing locally but when i went live o got a 403 verification failed issue adding the decorator tot he page view fixed this