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 condocument.cookie. Se un attaccante riesce a iniettare JavaScript nella pagina, non potra comunque leggere il cookie di sessioneuse_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 nuovocookie_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 automaticamenteSameSite=Lax— configurato insetLifeTime(), 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 congetFlashedErrors()per mostrarli accanto ai campi del formflashOldInput(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 loginAUTH_USER_ID— ID dell'utente correnteAUTH_SESSION_ID— riferimento server-side alla sessione di autenticazioneLAST_PING— timestamp dell'ultima attivitaLOGGED_IN— flag booleano per check rapidiIP— indirizzo IP al momento del login, per validazioneDEVICE— 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.