mardi 4 août 2015

How to retrieve/provide a CSRF token to/from Django as an API

I'm working on a project that uses the Django REST Framework as a backend (let's say at api.somecompany.com but has a React.js frontend (at www.somecompany.com) not served by Django that makes AJAX requests.

I can't, therefore, use Django's traditional method of having the template include the CSRF token like this <form action="." method="post">{% csrf_token %}

I can make a request to Django REST Framework's api-auth\login\ url, which will return this header: Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ - but I can't then retrieve this cookie to send back with my AJAX requests with X-CSRFToken (my understanding is of the separate subdomain), and it doesn't seem to be included automatically.

Here's my relevant code:

// using jQuery
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 csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    }
});

As the page loads I call this to make sure I have a token:

$.ajax(loginUrl, { method: "OPTIONS", async: false })
    .done(function(data, textStatus, jqXHR) {
        console.log(jqXHR)
        app.csrftoken@ = $.cookie("csrftoken")
        console.log($.cookie("csrftoken"))
        console.log(app.csrftoken)
    })
    .fail(function(jqXHR, textStatus, errorThrown) {
        console.log(jqXHR)
    });

This isn't exactly clean but I haven't proven the concept to myself yet.

What is the 'correct' way of authenticating / protecting against CSRF when the frontend and backend are on different ports/domains?

Aucun commentaire:

Enregistrer un commentaire