Search code examples
ajaxdjangoposthttpsdjango-csrf

Django middleware throws 403 error with HTTPS POST using ajax


I'm new to many pieces here (Django/Ajax etc), so while I understand the high-level CSFR picture, I dont have a complete handle on the details.

I needed to convert a request from GET to PUT due to the larger amount of data being passed. High level, I'm making an AJAX POST API call to a django app over HTTPS. The call is made to the same domain from where the page is served.

However, I keep getting a 'CSRF cookie not set' error.

I'm using Django 1.4

To get past CSRF protection, I have included the X-CSFRToken as mentioned in other posts here in the header and included the {{ csrf_token }} tag in the data posted. However, it doesnt look like that tag gets replaced with the token. X-CSFRToken value gets sent as NULL on the request. Not sure why it doesnt get set.

I'm under the impression that I dont need to use ensure_csrf_cookie() in the page view as I get the cookie before the POST in ajaxSetup, but I tried that as well.

Ideas what I'm doing wrong?

Relevant code:

siteUrl = "https://localhost:8443/"

$.ajaxSetup({ 
     beforeSend: function(xhr, settings) {
         function getCookie(name) {
             var cookieValue = null;
             if (document.cookie && document.cookie != '') {
                 var cookies = document.cookie.split(';');
                 for (var i = 0; i < cookies.length; i++) {
                     var cookie = jQuery.trim(cookies[i]);
                 if (cookie.substring(0, name.length + 1) == (name + '=')) {
                     cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                     break;
                 }
             }
         }
         return cookieValue;
         }
         if (new RegExp("^"+siteUrl.replace("\\","\\\\")+".*").test(settings.url)) {
             // Only send the token to URLs from our site.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     } 
});


$.ajax({
    url: submitUrl,
    data: {'network_ids': JSON.stringify(network_ids),
            'csrfmiddlewaretoken': '{{ csrf_token }}'},
    type: 'POST',
    crossDomain: true,
    dataType: 'json',
    cotentType: 'application/json',
    success: function(mydata) {
        console.log(mydata);
    },
    error: function(jqXHR, textStatus, errorThrown) {alert(textStatus); alert(errorThrown)}
})

Solution

  • You have several choices: This code listing shows you getting the CSRF token from a cookie: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    getCookie('csrftoken');
    

    and assuming that the javascript function is submitting to a django view, you can tell that view to ignore csrf protection. https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#django.views.decorators.csrf.csrf_exempt

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def my_view(request):
        return HttpResponse('Hello world')