Sicurezza Web di Laravel: Che cos’è Cross-Site Request Forgery (CSRF) ?
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.
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 POST
, PUT
, PATCH
e DELETE
, 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.
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:
- 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