Django: Ajax POST and CSRF giving "403 Forbidden" responses

If you want to protect your site from cross site request forgery, you'll have to enable the CSRF protection middleware.

You can do that by adding "django.middleware.csrf.CsrfViewMiddleware" to your MIDDLEWARE_CLASSES setting.

Once that's done, you have one of two ways to protect yourself.

When rendering forms, you can either:

  • use {{ form }} to print the form automatically
  • or if rendering manually, use the {% csrf_token %} tag somewhere in the form

When it comes to AJAX however, you'll have to either:

  • rewrite the request in a Form (troublesome in most cases)
  • add the output of {{ csrf_token }} (this one is not a tag) into an element and manually append it on every Ajax POST request
  • use a little jQuery snippet to automatically add in an "X-CSRFToken" header to each POST request

The third method is by far the easiest, and this snippet comes straight from the Django docs!

$(document).ajaxSend(function(event, 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]);

// 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;
}

function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host;
// host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;

// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}

function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});

Apparently this snippet will not work for jQuery v1.5 so you have to be using something newer.

Source:

 
Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog