Protezione CSFR

Intro

Le richieste di cross-site forgery sono un tipo di attacco malevolo in cui vengono eseguiti comandi non autorizzati a nome di un utente autenticato. Fortunatamente, Laravel semplifica la protezione della tua applicazione dagli attacchi di cross-site request forgery (CSRF).

Spiegazione della vulnerabilità

Nel caso in cui non tu sia familiare con le cross-site request forgeries, discutiamo di un esempio di come questa vulnerabilità può essere sfruttata. Immagina che la tua applicazione abbia una route /user/email che accetta una richiesta POST per cambiare l’indirizzo email dell’utente autenticato. Molto probabilmente, questa route si aspetta che un campo di input email contenga l’indirizzo email che l’utente desidera utilizzare.

Senza la protezione CSRF, un sito web malevolo potrebbe creare un modulo HTML che punti alla route /user/email della tua applicazione e invii l’indirizzo email del malintenzionato:

<form action="https://your-application.com/user/email" method="POST">
    <input type="email" value="malicious-email@example.com">
</form>
 
<script>
    document.forms[0].submit();
</script>

Se il sito web malevolo invia automaticamente il modulo quando la pagina viene caricata, l’utente malevolo deve soltanto indurre un utente ignaro della tua applicazione a visitare il loro sito web e l’indirizzo email dell’utente sarà cambiato nella tua applicazione.

Per prevenire questa vulnerabilità, è necessario ispezionare ogni richiesta POST, PUT, PATCH o DELETE in arrivo per un valore segreto di sessione a cui l’applicazione malevola non può accedere.

Prevenzione delle richieste CSRF

Laravel genera automaticamente un “token” CSRF per ogni sessione utente attiva gestita dall’applicazione. Questo token viene utilizzato per verificare che l’utente autenticato sia effettivamente la persona che effettua le richieste all’applicazione. Poiché questo token è memorizzato nella sessione dell’utente e cambia ogni volta che la sessione viene rigenerata, un’applicazione malevola non può accedervi.

Il token CSRF della sessione corrente può essere accesso tramite la sessione della richiesta o tramite la funzione helper csrf_token:

use Illuminate\Http\Request;
 
Route::get('/token', function (Request $request) {
    $token = $request->session()->token();
 
    $token = csrf_token();
 
    // ...
});

Ogni volta che definisci un modulo HTML “POST”, “PUT”, “PATCH” o “DELETE” nella tua applicazione, dovresti includere un campo nascosto _token CSRF nel modulo in modo che il middleware di protezione CSRF possa convalidare la richiesta. Per comodità, puoi utilizzare la direttiva Blade @csrf per generare il campo di input del token nascosto:

<form method="POST" action="/profile">
    @csrf
 
    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

Il middleware App\Http\Middleware\VerifyCsrfToken, incluso nel gruppo di middleware web per impostazione predefinita, verificherà automaticamente che il token nell’input della richiesta corrisponda al token memorizzato nella sessione. Quando questi due token corrispondono, sappiamo che l’utente autenticato sta iniziando la richiesta.

CSRF Tokens & SPAs

Se stai costruendo un’applicazione a pagina singola (SPA) che utilizza Laravel come backend API, dovresti consultare la documentazione di Laravel Sanctum per informazioni su come autenticarti con la tua API e proteggerti dalle vulnerabilità CSRF.

Escludere gli URI dalla protezione CSRF

A volte potresti voler escludere un insieme di URI dalla protezione CSRF. Ad esempio, se stai utilizzando Stripe per elaborare pagamenti e stai utilizzando il loro sistema di webhook, dovrai escludere la route del gestore webhook di Stripe dalla protezione CSRF poiché Stripe non saprà quale token CSRF inviare alle tue rotte.

In genere, dovresti inserire questo tipo di rotte al di fuori del gruppo di middleware web che l’ App\Providers\RouteServiceProvider applica a tutte le route nel file routes/web.php. Tuttavia, puoi anche escludere le route aggiungendo i loro URI alla proprietà $except del middleware VerifyCsrfToken:

<?php
 
namespace App\Http\Middleware;
 
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
 
class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}

Per comodità, il middleware CSRF è automaticamente disabilitato per tutte le route durante l’esecuzione dei test.

X-CSRF-Token

Oltre a verificare il token CSRF come parametro POST, il middleware App\Http\Middleware\VerifyCsrfToken controllerà anche l’intestazione della richiesta X-CSRF-TOKEN. Potresti, ad esempio, memorizzare il token in un tag meta HTML:

<meta name="csrf-token" content="{{ csrf_token() }}">

In seguito, puoi istruire una libreria come jQuery ad aggiungere automaticamente il token a tutte le intestazioni delle richieste. Ciò offre una protezione CSRF semplice e comoda per le tue applicazioni basate su AJAX che utilizzano tecnologie JavaScript legacy:

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

X-XSRF-Token

Laravel memorizza il token CSRF corrente in un cookie XSRF-TOKEN cifrato, incluso in ogni risposta generata dal framework. Puoi utilizzare il valore del cookie per impostare l’intestazione della richiesta X-XSRF-TOKEN.

Questo cookie è principalmente inviato per comodità dello sviluppatore, poiché alcuni framework e librerie JavaScript, come Angular e Axios, inseriscono automaticamente il suo valore nell’intestazione X-XSRF-TOKEN nelle richieste dello stesso dominio.

Per impostazione predefinita, il file resources/js/bootstrap.js include la libreria Axios per le richieste HTTP, la quale invierà automaticamente l’intestazione X-XSRF-TOKEN per te.