2015-08-03 6 views
5

Sto lavorando a un progetto che utilizza il framework Django REST come backend (diciamo allo api.somecompany.com ma ha un frontend React.js (allo www.somecompany.com) non servite da Django che fa richieste AJAX.Come recuperare/fornire un token CSRF a/da Django come API

non posso, quindi, utilizzare il metodo tradizionale di Django di avere il modello includono il token CSRF in questo modo <form action="." method="post">{% csrf_token %}

posso fare una richiesta al api-auth\login\ url di Django REST quadro , che restituirà questa intestazione: Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ - ma non riesco quindi a recuperare questo cookie per rispedire indietro con le mie richieste AJAX h X-CSRFToken (la mia comprensione è del sottodominio separato) e non sembra essere inclusa automaticamente.

Ecco il mio codice rilevante:

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

Come la pagina viene caricata Io chiamo questo per assicurarsi che ho un token:

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

Questo non è esattamente pulito ma non ho provato il concetto a me stesso ancora.

Qual è il modo "corretto" di autenticazione/protezione contro CSRF quando il frontend e il backend si trovano su porte/domini diversi?

risposta

1

È possibile, in effetti, eseguire questo lavoro con la protezione CSRF, utilizzando una whitelist di origini richieste consentite.

Per fare in modo che funzioni, è necessario utilizzare Cross-Origin Resource Sharing (CORS). Per raggiungere questo obiettivo, ti consiglio di creare una classe middleware che configuri le credenziali di cross-sharing. C'è uno great gist che descrive come utilizzare parte della compilazione di intestazioni di richieste HTTP di origine incrociata. È possibile, se lo si desidera, inserire il token CSRF tramite il middleware in questo modo, modificando i valori di riferimento di origine per la richiesta.

L'app django-cors-headers fa questo per voi. Puoi vedere come hanno negoziato i token CSRF in their middleware file, se sei interessato.

Fare riferimento a Django REST CORS Docs per ulteriori informazioni (si consiglia di utilizzare le intestazioni django-cors).

Se continui ad avere problemi, provare:

  1. impostare il parametro crossDomain della richiesta AJAX per True. A volte, jQuery non elaborerà la richiesta se questo non è specificato.
  2. se ancora non si riceve l'intestazione del token nella richiesta, provare ad aggiungere il decoratore ensure_csrf_cookie() al metodo di visualizzazione. Occasionalmente, quando non c'è un tag modello {% csrf_token %} nella pagina (se non stai facendo il rendering di un modulo), Django non includerà affatto il token nella richiesta.
+0

Penso di averlo già coperto - la mia richiesta non ha esito negativo per motivi CORS. Il mio problema, per quanto posso dire, è che la mia prima richiesta (quella di 'OPTIONS') non sta impostando il cookie 'csrftoken', quindi non posso leggerlo per aggiungerlo come intestazione, o farlo inviare automaticamente con una successiva richiesta. Effettuare direttamente una richiesta (non usando AJAX) imposta i cookie correttamente. C'è qualcosa che impedisce il settaggio del cookie? – jimbofreedman

+0

In questo caso, posso pensare ad altre due cose che potrebbero andare storte: in primo luogo, assicurati di impostare il parametro 'crossDomain' della richiesta AJAX su' True' come descritto in api.jquery.com/jQuery. ajax. È anche probabile che, se non includi un tag modello CSRF sulla pagina che stai rendendo (cioè la pagina non ha forma), Django potrebbe non includere il token nell'intestazione per impostazione predefinita. Puoi usare il decoratore 'ensure_csrf_cookie (view)' attorno alla tua vista per forzarlo (vedi https://docs.djangoproject.com/en/dev/ref/csrf/#django.views.decorators.csrf.ensure_csrf_cookie) – ilkahnate