Come usare la protezione CSRF di Django

Per trarre vantaggio dalla protezione di CSRF nelle tue view, segui questi passi:

  1. Il middleware CSRF viene attivato di default nell’impostazione MIDDLEWARE. Se sovrascrivi quella impostazione, ricorda che 'django.middleware.csrf.CsrfViewMiddleware' dovrebbe stare prima di ogni middleware per le view che assume che ci si sia già occupati degli attacchi CSRF.

    Se l’hai disabilitato, cosa che non è raccomandata, puoi usare csrf_protect() sulle specifiche view che vuoi proteggere (vedi sotto).

  2. In ogni template che utilizzi un form POST, usa il tag csrf_token dentro l’elemento <form> se il form fa riferimento ad un URL interna, per es.:

    <form method="post">{% csrf_token %}
    

    Questo non si dovrebbe fare per i form POST che hanno come destinazione URL esterne, perchè questo esporrebbe il token CSRF, aprendo una vulnerabilità.

  3. Nelle funzioni di view corrispondenti, assicurati che venga utilizzato RequestContext per fare render della response così che {% csrf_token %} funzioni correttamente. Se stai usando la funzione render(), view generiche o app contrib, se già coperto perchè usano già tutte RequestContext.

Utilizzare la protezione CSRF con AJAX

Anche se il metodo di cui sopra può essere utilizzato per le richieste AJAX POST, pone qualche inconveniente: devi ricordare di passare il token CSRF con i dati POST ad ogni richiesta POST. Per questo, esiste un metodo alternativo: in ogni XMLHttpRequest, imposta un header personalizzato X-CSRFToken (come specificato nell’impostazione CSRF_HEADER_NAME) con il valore del token CSFR. Spesso questo è più semplice, perchè molti framework Javascript offrono hooks che permettono di impostare le intestazioni per ogni richiesta.

Prima di tutto, devi ottenere il token CSRF. Come ottenerlo dipende dal fatto che siano abilitate o meno le impostazioni CSRF_USE_SESSIONS e CSRF_COOKIE_HTTPONLY .

Impostare il token sulla richiesta AJAX

Infine, avrai bisogno di impostare l’intestazione della tua request AJAX. Usando l’API fetch():

const request = new Request(
    /* URL */,
    {
        method: 'POST',
        headers: {'X-CSRFToken': csrftoken},
        mode: 'same-origin' // Do not send CSRF token to another domain.
    }
);
fetch(request).then(function(response) {
    // ...
});

Usare la protezione CSRF nei template Jinja2

Il backend di template di Django Jinja2 aggiunge {{ csrf_input }} al context di tutti i template che è equivalente a {% csrf_token %} nel linguaggio di template di Django. Per esempio:

<form method="post">{{ csrf_input }}

Usare il metodo decoratore

Piuttosto che inserire CsrfViewMiddleware come protezione totale, puoi usare il decoratore csrf_protect(), che ha esattamente la stessa funzionalità su particolari view che abbiano bisogno di protezione. Devono essere usati entrambi sulle view che inseriscono il token CSRF in output e su quelle che accettano i dati POST dai form. (Sono spesso le stesse funzioni anche se non è sempre così).

L’uso del decoratore di per sè non è raccomandato poichè se dimentichi di usarlo, ci sarà un buco nella sicurezza. La strategia “a tutto tondo” di usare entrambe va bene ed introdurrà un overhead minimo.

Gestire le richieste rifiutate

Per impostazione predefinita, una response “403 Forbidden” viene inviata all’utente se la request in ingresso fallisce sui controlli fatti da CsrfViewMiddleware. Questo dovrebbe accadere solo se c’è un vero Cross Site Request Forgery o quando, a causa di un errore di programmazione, il token CSRF non è stato incluso nel POST del form.

La pagina di errore, in ogni caso, non è molto amichevole quindi potresti voler fornire la tua per gestire questa condizione. Per fare ciù, imposta il setting CSRF_FAILURE_VIEW.

I fallimenti CSRF sono registrati come warning nel logger django.security.csrf.

Usare la protezione CSRF con il caching

Se il tag di template csrf_token è utilizzato da un template (o viene chiamata in qualche modo la funzione get_token), CsrfViewMiddleware aggiungerà un cookie ed una intestazione Vary: Cookie alla response. Questo significa che il middleware si comporterà bene con il middleware di cache se viene usato come suggerito (UpdateCacheMiddleware viene prima di tutti gli altri middleware).

In ogni caso, se usi decoratori di cache su view specifiche, il middleware CSRF non sarà ancora in grado di impostare l’intestazione Vary sul cookie CSRF e la response sarà messa in cache senza che ci sia. In questo caso, su qualsiasi view che richieda l’inserimento di un cookie CSRF dovresti usare prima il decoratore django.views.decorators.csrf.csrf_protect():

from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect


@cache_page(60 * 15)
@csrf_protect
def my_view(request):
    ...

Se stai usando view basate su classi, puoi fare riferimento a Decorating class-based views.

I test e la protezione CSRF

CsrfViewMiddleware` sarà generalmente un grosso ostacolo nel test delle funzioni delle view, a causa della necessità del token CSRF che deve essere inviato ad ogni richiesta POST. Per questo motivo, il client HTTP di Django per i test è stato modificato per impostare un flag sulle richieste che rilassa il middleware ed il decoratore ``csrf_protect in modo che non rifiutino più le richieste. In ogni altro aspetto (per es. invio di cookie), si comportano nello stesso modo.

Se, per qualche motivo, vuoi che il client di test esegue i controlli CSRF, puoi creare un’istanza del client di test che imponga i controlli CSRF:

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

Casi limite

Alcune view hanno requisiti inusuali, il che significa che non ricadono nei pattern normali qui illustrati. Un certo numero di utility possono essere utili in queste situazioni. Gli scenari in cui potrebbero essere necessarie sono descritti nella seguente sezione.

Disabilitare la protezione CSRF solo per alcune view

Molte view richiedono la protezione CSRF ma alcune non ne hanno bisogno.

Soluzione: invece che disabilitare il middleware ed applicare csrf_protect a tutte le view che ne hanno bisogno, abilita il middleware ed usa csrf_exempt().

Impostare il token quando non viene usato CsrfViewMiddleware.process_view()

Ci sono casi in cui CsrfViewMiddleware.process_view potrebbe non aver girato prima della tua view - per esempio gli handler 404 e 500 - ma hai ancora bisogno del token CSRF in un form.

Soluzione: usa requires_csrf_token()

Includere il token CSRF in una view non protetta

Potrebbero esserci alcune view che non sono protette e sono esenti con csrf_exempt ma hanno ancora bisogno di includere un token CSRF.

Soluzione: usa csrf_exempt() seguito da requires_csrf_token() (cioè requires_csrf_token dovrebbe essere il decoratore più interno).

Proteggere una view per un solo percorso

Una view ha bisogno di protezione CSRF solo in alcune condizioni e non deve averlo per tutte le altre.

Soluzione: usa csrf_exempt() per l’intera funzione di view e csrf_protect() per il percorso che necessita di protezione. Esempio:

from django.views.decorators.csrf import csrf_exempt, csrf_protect


@csrf_exempt
def my_view(request):
    @csrf_protect
    def protected_path(request):
        do_something()

    if some_condition():
        return protected_path(request)
    else:
        do_something_else()

Proteggere una pagina che usa AJAX senza un form HTML

Una pagina fa una richiesta AJAX e non ha un form HTML con un csrf_token che farebbe partire il cookie CSRF.

Soluzione: usa ensure_csrf_cookie() sulla view che invia la pagina.

Protezione CSRF in applicazioni riusabili

Dal momento che è possibile per lo sviluppatore disabilitare CsrfViewMiddleware, tutte le view rilevanti nelle app contrib usano il decoratore csrf_protect per assicurare la sicurezza di queste applicazioni contro CSRF. Si raccomanda agli sviluppatori di applicazioni riutilizzabili che vogliano le stesse garanzie di usare anche il decoratore csrf_protect sulle proprie view.

Back to Top