Sessioni sicure: flash data, timeout e protezione anti-fixation — articolo

> Sessioni sicure: flash data, timeout e protezione anti-fixation

Deep dive su SessionStorage: configurazione cookie sicuri, flash messages, timeout per inattivita e rigenerazione ID.

Luigi Iadicola
~6 min lettura
#Backend #Security #Session
Sessioni sicure: flash data, timeout e protezione anti-fixation
Sessioni sicure: flash data, timeout e protezione anti-fixation

Perche la sessione e il punto piu sensibile

In un'applicazione web, la sessione e il legame tra il browser dell'utente e il suo stato sul server. Chi controlla la sessione controlla l'identita dell'utente. Per questo la gestione delle sessioni non e solo una questione di comodita — e una questione di sicurezza. Un cookie di sessione rubato o un ID di sessione prevedibile possono dare accesso completo all'account di un utente.

SessionStorage e il singleton che gestisce tutto cio che riguarda le sessioni in Soft PHP MVC. Il pattern singleton qui e obbligato dalla natura stessa delle sessioni PHP: session_start() puo essere chiamato una sola volta per richiesta, e avere piu istanze che tentano di manipolare la sessione porterebbe a race condition e comportamenti imprevedibili.

Cookie hardening: i flag che contano

Nel costruttore, prima di avviare la sessione, SessionStorage configura i flag di sicurezza dei cookie:

  • cookie_httponly = 1 — il cookie di sessione non e accessibile da JavaScript. Questo neutralizza la classe piu comune di attacchi XSS che mirano a rubare il session ID con document.cookie. Se un attaccante riesce a iniettare JavaScript nella pagina, non potra comunque leggere il cookie di sessione
  • use_strict_mode = 1 — PHP rifiuta ID di sessione non inizializzati dal server. Senza strict mode, un attaccante potrebbe impostare un cookie di sessione con un ID arbitrario (session fixation) e aspettare che la vittima lo usi. Con strict mode, PHP ignora gli ID che non corrispondono a sessioni esistenti e ne genera uno nuovo
  • cookie_secure — attivato solo se la connessione e HTTPS. Impedisce al browser di inviare il cookie su connessioni HTTP non cifrate, dove potrebbe essere intercettato. Il check e dinamico: in sviluppo locale su HTTP il flag non viene impostato, in produzione su HTTPS si attiva automaticamente
  • SameSite=Lax — configurato in setLifeTime(), impedisce l'invio del cookie in richieste cross-site di tipo POST. Questo fornisce una protezione aggiuntiva contro CSRF: anche se un sito malevolo invia un form POST verso la nostra applicazione, il browser non includera il cookie di sessione

Questi quattro flag, combinati, chiudono i vettori di attacco piu comuni sulle sessioni. Non sono opzionali o consigliati — sono il minimo indispensabile per una gestione sessioni che si possa definire sicura.

Lifetime e timeout: due concetti diversi

SessionStorage distingue tra lifetime e timeout, due concetti che spesso vengono confusi:

Lifetime e la durata massima assoluta della sessione. Dopo questo tempo, la sessione scade indipendentemente dall'attivita dell'utente. Viene impostato sia lato server (gc_maxlifetime) che lato client (cookie_lifetime). Il metodo setLifeTime() sincronizza entrambi i valori e aggiorna i parametri del cookie per garantire coerenza.

Timeout e il periodo di inattivita dopo il quale la sessione viene invalidata. Se l'utente non fa richieste per N minuti, la sessione viene distrutta al prossimo accesso. Questo protegge contro il caso in cui un utente dimentica il browser aperto su un computer condiviso. Il timestamp LAST_ACTIVITY viene aggiornato a ogni richiesta e confrontato con il timeout configurato.

In pratica: un lifetime di 8 ore significa che dopo 8 ore l'utente deve riautenticarsi anche se sta usando attivamente l'applicazione. Un timeout di 30 minuti significa che dopo 30 minuti di inattivita la sessione scade. Entrambi servono e hanno scopi diversi.

Flash session: messaggi che vivono una sola richiesta

Il pattern flash session e fondamentale per le applicazioni web con redirect. Dopo un form submit, il controller processa i dati, esegue un redirect (PRG pattern), e nella pagina di destinazione vuole mostrare un messaggio di successo o gli errori di validazione. Ma il redirect e una nuova richiesta — i dati del controller precedente non sono piu disponibili.

Le flash session risolvono questo: salvano dati nella sessione sotto la chiave _flash, e il metodo getFlash() li legge e li cancella in un'unica operazione. Il dato e disponibile esattamente per una richiesta, poi sparisce. Non si accumula, non serve pulirlo manualmente.

SessionStorage offre metodi specializzati per i due casi d'uso piu comuni:

  • flashErrors(array $errors) — salva gli errori di validazione in flash. Il controller li imposta dopo una validazione fallita, e la view li recupera con getFlashedErrors() per mostrarli accanto ai campi del form
  • flashOldInput(array $data) — salva i dati del form in flash per ripopolare i campi dopo un errore. L'utente non deve riscrivere tutto da capo: getOldInput('email') restituisce il valore inserito nel submit precedente

Il flusso tipico e: submit → validazione fallisce → flashErrors($errors) + flashOldInput($request->all()) → redirect back → la view legge errori e old input → li mostra nel form. Tutto questo senza variabili globali, senza parametri nell'URL, e senza stato che persiste oltre la richiesta successiva.

Rigenerazione ID: prevenire session fixation

Il metodo regenerateId() e un wrapper attorno a session_regenerate_id() con un check di sicurezza: verifica che la sessione sia effettivamente attiva prima di tentare la rigenerazione. Viene chiamato dopo il login per invalidare il vecchio session ID e crearne uno nuovo.

Perche e importante? In un attacco di session fixation, l'attaccante ottiene un session ID valido (ad esempio visitando il sito) e lo imposta nel browser della vittima (tramite un link crafted o XSS). Quando la vittima si autentica, il suo login viene associato al session ID che l'attaccante gia conosce. Rigenerando l'ID dopo il login, il vecchio ID diventa inutile e l'attaccante perde l'accesso.

Il parametro $deleteOldSession = true di default cancella i dati della vecchia sessione dal server, impedendo che vengano riutilizzati. E un dettaglio importante: senza la cancellazione, i file di sessione vecchi si accumulerebbero sul server e un attaccante con il vecchio ID potrebbe ancora leggerne i dati.

Sessioni di autenticazione: cosa viene salvato

Quando un utente si autentica, il framework salva in sessione una serie di informazioni che vanno oltre il semplice ID utente:

  • AUTH_TOKEN — token di autenticazione generato al login
  • AUTH_USER_ID — ID dell'utente corrente
  • AUTH_SESSION_ID — riferimento server-side alla sessione di autenticazione
  • LAST_PING — timestamp dell'ultima attivita
  • LOGGED_IN — flag booleano per check rapidi
  • IP — indirizzo IP al momento del login, per validazione
  • DEVICE — User-Agent, per rilevamento di anomalie

L'IP e il device fingerprinting servono come strato di difesa aggiuntivo: se una sessione risulta provenire da un IP o un browser diverso da quello originale, l'AuthService puo invalidarla preventivamente. Non e un sistema antifrode completo, ma alza significativamente la barra per un attaccante che ha rubato solo il cookie di sessione.

Il metodo destroy(): pulizia totale

Quando la sessione viene distrutta (logout o timeout), destroy() non si limita a chiamare session_destroy(). Prima svuota $_SESSION con un array vuoto, poi chiama session_unset() per liberare tutte le variabili di sessione, e infine session_destroy() per eliminare i dati lato server. Questa tripla pulizia garantisce che non restino residui — ne in memoria, ne nel session storage, ne nei cookie.

altri articoli