csrf token laravel

In questo tutorial di Laravel parliamo di Sicurezza Web e come proteggere una applicazione web da Cross-Site Request Forgery o attacchi CSRF.

CSRF è un’attività dannosa compiuta da un utente malintenzionato, che esegue azioni per conto di un utente autenticato, a danno della sicurezza web. Fortunatamente, Laravel fornisce gli strumenti per prevenire questo tipo di vulnerabilità.

Tempo di lettura stimato: 5 minuti

Cos’è CSRF?

Gli attacchi CSRF dirottano le sessioni utente. Lo fanno inducendo un utente a inviare una richiesta tramite tag di moduli nascosti o URL dannosi (immagini o collegamenti) all’insaputa dell’utente.

Questo attacco porta a un cambiamento nello stato della sessione utente, perdite di dati e a volte gli hacker possono manipolare i dati degli utenti finali in un’applicazione.

sicurezza web csrf

L’immagine sopra illustra uno scenario in cui la sicurezza web viene violata. La vittima invia una richiesta cliccando su un link (ricevuto), inviando una richiesta a un website server che produrrà effetti voluti dall’hacker, che entra in possesso delle informazioni utili per accedere e manipolare del website server.

Come prevenire le richieste CSRF

Per migliorare la sicurezza web delle tue applicazioni, in ogni sessione utente, Laravel genera token protetti che utilizza per garantire che l’utente autenticato sia quello che richiede l’applicazione.

Poiché questo token cambia ogni volta che viene rigenerata una sessione utente, un utente malintenzionato non può accedervi.

Ogni volta che c’è una richiesta di modifica delle informazioni dell’utente sul lato server (back-end) come POSTPUTPATCHDELETE, devi includere la direttiva @csrf nella richiesta del modulo blade HTML. Il @csrf è quindi una direttiva Blade utilizzata per generare un token nascosto convalidato dall’applicazione.

La direttiva Blade è la sintassi utilizzata all’interno del motore di modelli di Laravel chiamato Blade . Per creare un file blade bisogna dargli un nome – nel nostro caso form – seguito dall’estensione del blade. Ciò significa che il file avrà il nome form.blade.php.

Si utilizza il file blade per eseguire il rendering delle visualizzazioni per gli utenti sulla pagina Web. Ci sono un paio di direttive predefinite o sintassi abbreviate blade che puoi usare. Ad esempio, @if controlla se una condizione è soddisfatta, @empty controlla se i record non sono vuoti, @auth controlla se un utente è autenticato e così via.

Ma torniamo alla direttiva @csrf. Ecco come lo usi:

<form method="POST" action="{{route('pay')}}">

    @csrf
    
</form>

Le versioni precedenti di Laravel avevano una impostazione diversa: entrambi funzionano e fanno la stessa cosa.

<form method="POST" action="{{route('pay')}}">
    
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
    
</form>

Quando il token CSRF non è presente nella richiesta del modulo che viene inviato o se sembra non valido, Laravel genera un messaggio di errore “Pagina scaduta” con un codice di stato 419.

sicurezza web page expired

Come e dove avviene la verifica CSRF

Il middleware VerifyCsrfToken gestisce la verifica CSRF all’interno dell’applicazione Laravel. Il middleware è registrato in Kernel.php e si trova nella directory app/Http/Middleware. Ciò significa che il middleware viene attivato per le richieste all’interno del Web, non correlate alle API.

protected $middlewareGroups = [
        'web' => [
           .
           .
           .
           .
           .
            \App\Http\Middleware\VerifyCsrfToken::class,
        ],
    ];

Il middleware VerifyCsrfToken estende la classe Illuminate\Foundation\Http\Middleware\VerifyCsrfToken, cioè la verifica CSRF è definita all’interno della classe.

Approfondiamo per scoprire come Laravel gestisce la verifica CSRF.

All’interno della classe, abbiamo la funzione tokensMatch.

protected function tokensMatch($request)
{
     $token = $this->getTokenFromRequest($request);

     return is_string($request->session()->token()) &&
            is_string($token) &&
            hash_equals($request->session()->token(), $token);
}

nel codice determina se la sessione e i token CSRF di input corrispondono.

La funzione fa due cose:

  1. ricava $this->getTokenFromRequest il token dalla richiesta in arrivo allegata tramite un campo nascosto o l’intestazione della richiesta. Il token viene decrittografato e quindi restituito alla variabile token.
protected function getTokenFromRequest($request)
{
    $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

    if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
        try {
            $token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
        } catch (DecryptException $e) {
            $token = '';
            }
    }

    return $token;
}

Nel codice ottiene token dall’intestazione

2. Eseguire il cast sia del token di richiesta che della sessione su una stringa e quindi utilizzare hash_equals integrato in PHP per confrontare se entrambe le stringhe sono uguali. Il risultato di questa operazione è sempre bool (true) o (false) .

Esclusione degli URI dalla protezione CSRF

Potremmo avere la necessità di escludere un set di URI dalla protezione CSRF. Ad esempio, se utilizziamo paypal  per elaborare i pagamenti e utilizzi il loro sistema webhook, dovrai escludere il percorso del gestore webhook PayPal dalla protezione CSRF poiché PayPal non saprà quale token CSRF inviare ai tuoi percorsi.

In genere, dovrai posizionare questi tipi di percorsi all’esterno del gruppo web middleware che Laravel applica a tutti i percorsi nel file routes/web.php. Possiamo anche escludere percorsi specifici fornendo i relativi URI al metodo validateCsrfTokens nel file dell’applicazione bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ]);
})

Letture Correlate

Ercole Palmeri

Autore