La gestione delle sessioni è una disciplina per creare, validare e distruggere lo stato lato server che lega le richieste HTTP a un utente. HTTP di per sé non ricorda nulla – ogni richiesta arriva come una sconosciuta – e così le applicazioni colmano il divario con una sessione: un record lato server più un ID casuale che il browser presenta a ogni richiesta. L’intuizione di sicurezza da cui discende tutto il resto: quell’ID equivale a una credenziale completa – chi lo possiede è l’utente, senza password – e merita quindi generazione, trasporto e distruzione di livello password.
Punti chiave
| Domanda | Risposta |
|---|---|
| Il meccanismo | Accesso → record sul server + ID casuale in un cookie → ID restituito a ogni richiesta |
| L’intuizione | L’ID di sessione è una credenziale – ID rubato = account compromesso |
| Il ciclo di vita | Creare → rigenerare all’accesso/al cambio di privilegio → validare → far scadere → distruggere lato server |
| I numeri | ≥64 bit di entropia CSPRNG · 15–30 min di inattività · poche ore in assoluto |
| Il bug classico | Un “logout” che elimina il cookie ma lascia vivo il record sul server |
Il ciclo di vita in cinque fasi
1 CREARE all'accesso: record lato server + ID casuale (≥64 bit, CSPRNG)
2 RIGENERARE a OGNI cambio di privilegio – accesso, elevazione di ruolo,
cambio password – emettere un nuovo ID e ritirare il vecchio
(elimina la fixation)
3 VALIDARE a ogni richiesta: l'ID esiste, non è scaduto, è dell'utente
4 SCADERE due orologi imposti dal server: inattività + timeout assoluto
5 DISTRUGGERE logout = eliminare PRIMA il record sul server, poi il cookie
(il "logout" solo-cookie lascia la sessione viva per un ladro)
Le sessioni come oggetti di prima classe, interrogabili – il ciclo di vita con delle maniglie:
// JavaScript / Node.js — Back4app JS SDK
// Sessions are objects: queryable, per-device, revocable
const user = await Parse.User.logIn('ada', password); // Session object created
console.log(user.getSessionToken()); // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
const sessions = await new Parse.Query(Parse.Session).find();
// Logout = server-side destroy — the token dies NOW
await Parse.User.logOut(); // Flutter / Dart — Back4app Flutter SDK
// Sessions are objects: queryable, per-device, revocable
final user = ParseUser('ada', password, null);
await user.login(); // Session object created
print(user.sessionToken); // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
final sessions = await QueryBuilder(ParseSession.forQuery()).query();
// Logout = server-side destroy — the token dies NOW
await user.logout(); // iOS / Swift — Back4app Swift SDK
// Sessions are objects: queryable, per-device, revocable
let user = try await User.login(username: "ada", password: password)
print(user.sessionToken ?? "") // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
let sessions = try await ParseSession.query().find()
// Logout = server-side destroy — the token dies NOW
try await User.logout() // Android / Kotlin — Back4app Android SDK
// Sessions are objects: queryable, per-device, revocable
val user = ParseUser.logIn("ada", password) // Session object created
println(user.sessionToken) // r:… — the credential
// "Active devices" UI: each login is a Session row (ACL: owner-only)
val sessions = ParseQuery.getQuery(ParseSession::class.java).find()
// Logout = server-side destroy — the token dies NOW
ParseUser.logOut() Cookie di sessione: i flag e che cosa blocca ciascuno
La corrispondenza che nessuna pagina di classifica mette in tabella – ogni flag è la pietra tombale di un attacco con un nome:
| Flag | Che cosa fa | Attacco che blocca |
|---|---|---|
Secure | Il cookie viaggia solo su HTTPS | Sniffing di rete |
HttpOnly | Invisibile a JavaScript | Furto di cookie via XSS |
SameSite=Lax/Strict | Trattenuto sulle richieste cross-site | CSRF |
Prefisso __Host- | Vincola il cookie all’origine, nessun trucco di sottodominio | Fixation via sottodomini |
| (senza Max-Age/Expires) | Muore con la sessione del browser | Sessioni stantie su macchine condivise |
Semantica conforme alla RFC 6265, con i dettagli pratici su MDN. Tutti e cinque insieme sono la linea di base, non la configurazione irrobustita.
Gli attacchi, ciascuno con la sua difesa
Hijacking – rubare un ID valido (sniffing su HTTP in chiaro, XSS, malware) e presentarlo; il server vede l’utente. Difesa: TLS in ogni punto, la tabella di flag qui sopra, durate di vita brevi, monitoring dei viaggi impossibili. Fixation – l’inversione che vale la pena capire a livello meccanico: l’attaccante dà alla vittima un ID prima dell’accesso (link costruito ad arte, cookie piazzato); la vittima si autentica; l’ID noto all’attaccante è ora una sessione connessa. Difesa in una sola mossa: rigenerare l’ID al momento dell’autenticazione – l’ID pre-accesso noto all’attaccante perde ogni valore nell’istante in cui i privilegi si agganciano, e i server rigorosi rifiutano qualsiasi ID che non abbiano coniato loro. Furto via XSS – lo script iniettato legge il cookie; HttpOnly rimuove quella lettura, che è limitazione del danno mentre l’XSS stesso viene corretto. CSRF – il browser, servizievole, allega i cookie alle richieste cross-site contraffatte; SameSite più i token anti-CSRF chiudono la porta.
Sessioni vs. JWT
| Sessioni lato server | JWT | |
|---|---|---|
| Dove vive lo stato | Sul server | Dentro il token |
| Revoca | Istantanea – eliminare il record | Attende exp, o uno stato di denylist |
| Costo per richiesta | Una lettura nello store | Verifica della firma |
| Scalabilità tra servizi | Richiede uno store condiviso | Verifica chiunque abbia la chiave |
Il punto cruciale è la revocabilità, e si tratta di una decisione di architettura, non di una casella di funzionalità: le sessioni possono morire nell’istante in cui si decide; i token stateless no, e ogni aggiramento reintroduce lo stato che si era tolto. La voce sui JWT difende il lato stateless; l’argomento di questo articolo è che cosa richiede uno stateful fatto bene.
I numeri che rendono la cosa concreta
La cheat sheet di OWASP fissa l’entropia a ≥64 bit da un CSPRNG – sedici caratteri esadecimali casuali, abbastanza perché forzare gli ID richieda secoli a ritmi di richiesta realistici – senza nulla di significativo codificato nell’ID. I timeout corrono su due orologi: inattività (2–5 minuti per le applicazioni di alto valore, 15–30 per quelle comuni) e assoluto (poche ore, che chiude anche le sessioni attive perché un ID rubato abbia un tetto rigido). Le linee guida del NIST sull’identità digitale formalizzano la stessa forma: al livello di assurance 2, riautenticazione dopo al massimo 1 ora di inattività e almeno ogni 24 ore in ogni caso (12 ore al livello 3).
Scalare le sessioni: sticky routing vs. store condiviso
| Sticky session | Store condiviso (stile Redis) | |
|---|---|---|
| Come | Il load balancer fissa utente → server | Tutti i server leggono un solo session store |
| Il server muore | Le sue sessioni muoiono con lui | Gli utenti non se ne accorgono |
| Scalabilità | Carico disomogeneo, drain a ogni deployment | Qualsiasi server, qualsiasi richiesta |
| Verdetto | Una pezza di routing | L’architettura |
La memoria di sessione in-process funziona su esattamente un server. Lo sticky routing la allunga – e trasforma ogni server in un piccolo disservizio in attesa di disconnettere utenti. La risposta standard è uno store condiviso in memoria (Redis, Memcached) oppure il database: lo stato di sessione diventa infrastruttura e il livello web diventa stateless – la stessa proprietà che rende attraenti le architetture a JWT, ottenuta però conservando la revoca istantanea.
Le sessioni come funzionalità di prodotto
Il livello di sicurezza fa anche da UX quando le sessioni sono visibili: una schermata “sessioni attive” che elenca ogni dispositivo con ora e luogo dell’accesso, un pulsante “esci da tutti i dispositivi” e la revoca automatica di tutte le sessioni al cambio password o in caso di compromissione sospetta. Gli utenti ci leggono sicurezza; chi sviluppa dovrebbe leggerci un requisito sull’architettura – le sessioni devono essere oggetti interrogabili con un proprietario, non blob opachi in una cache, che è precisamente dove i session store progettati per la sola lettura non arrivano.
Casi d’uso tipici
- Stato di accesso di un’app web – il caso canonico: sessioni portate dal cookie con il set completo di flag.
- Carrelli e percorsi e-commerce – stato multi-passo che deve sopravvivere alla navigazione, ma non alla settimana.
- Banche e applicazioni di alto valore – timeout di inattività brevi, tetti assoluti, MFA di step-up a sessione in corso per le azioni sensibili.
- Gestione dei dispositivi – sessioni per dispositivo che alimentano il “disconnetti il telefono che mi hanno rubato”.
- Pannelli di amministrazione – dove la rigenerazione all’elevazione di privilegio e i timeout aggressivi si guadagnano il posto.
Sessioni o token? Matrice decisionale
| Situazione | Scegliere |
|---|---|
| App web su un solo dominio | Le sessioni – più semplici e revocabili all’istante |
| Il blocco immediato non è negoziabile | Le sessioni (o i token più lo stato che si voleva evitare) |
| Molti servizi verificano in autonomia | I JWT |
| App mobile su un BaaS | I session token della piattaforma – revocabili, già pronti |
| Scalabilità orizzontale con le sessioni | Uno store condiviso, non lo sticky routing |
| I “dispositivi attivi” come funzionalità | Le sessioni come oggetti interrogabili |
Limiti e trade-off
- Lo store è infrastruttura sull’hot path. Ogni richiesta lo legge; la sua latenza diventa la latenza dell’applicazione, il suo disservizio è il logout di tutti.
- Il cross-domain è scomodo. I cookie si legano alle origini; un’API consumata da molte parti spinge verso i token – l’ibrido onesto è spesso sessioni per l’app, token per l’API.
- I timeout pesano sugli utenti. Ogni logout per inattività è attrito; i numeri qui sopra sono decisioni di rischio, non costanti, e meritano un avallo di prodotto.
- La revoca richiede un impianto che l’utente vede. La revoca istantanea vale solo se il cambio password e l‘“esci da tutti i dispositivi” la attivano davvero – vanno collegati gli eventi, non solo la capacità.
- Le sessioni ereditano la politica dei cookie. Le evoluzioni sui cookie di terze parti e il lavoro dei browser sulla privacy spostano continuamente il terreno; i cookie di sessione first-party restano terreno sicuro, ma conviene restarci di proposito.
Sessioni su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. Qui le sessioni sono gli “oggetti interrogabili” che questo articolo non smette di chiedere – letteralmente: ogni accesso crea un oggetto Session che porta il token revocabile, il suo utente, il contesto di creazione e la scadenza, delimitato da ACL perché ciascuno veda solo le proprie. I tab di codice ne mostrano le conseguenze: una schermata “dispositivi attivi” è una query; il logout è un destroy lato server che uccide subito il token in ogni punto; un cambio password può revocare ogni sessione; e i trigger Cloud Code sono il punto di aggancio per le regole di step-up e i registri di audit. Ciclo di vita, revoca e funzionalità di prodotto poggiano sulla stessa primitiva – le sessioni come dati – con la macchineria di entropia, archiviazione e validazione gestita dalla piattaforma.
Domande frequenti
Come funzionano le sessioni?
All'accesso il server crea un record di sessione ed emette un ID casuale in un cookie; il browser restituisce l'ID a ogni richiesta, il server recupera lo stato associato, e il record viene distrutto al logout o alla scadenza. L'ID è l'intera credenziale: chi lo presenta viene trattato come l'utente.
Qual è la differenza tra autenticazione a sessione e a token (JWT)?
Dove vive lo stato. Le sessioni lo tengono lato server: una lettura per richiesta, revocabile all'istante. I JWT lo portano dentro il token: nessuna lettura, verificabile da qualsiasi parte, ma valido fino alla scadenza qualunque cosa accada. Le sessioni si adattano alle app su un solo dominio che vogliono controllo; i token alle API e ai microservizi che vogliono portabilità.
Che cos'è il session hijacking e come si previene?
Consiste nel rubare un ID di sessione valido – con sniffing, XSS o malware – e presentarlo per impersonare l'utente senza conoscerne mai la password. Difese: HTTPS in ogni punto, flag HttpOnly e Secure sul cookie, ID a entropia elevata, durate di vita brevi, rigenerazione a ogni cambio di privilegio e monitoring delle anomalie.
Che cos'è la session fixation?
L'attaccante piazza un ID di sessione che già conosce – con un link costruito ad arte o un cookie di sottodominio – e attende che la vittima acceda con quello; l'ID noto diventa così una sessione autenticata. La correzione completa: emettere un ID interamente nuovo a ogni evento di autenticazione e rifiutare gli ID che il server non ha mai generato.
A cosa servono i flag del cookie di sessione?
Ognuno chiude una via di furto: Secure invia il cookie solo su HTTPS (blocca lo sniffing); HttpOnly lo nasconde a JavaScript (blocca il furto di cookie via XSS); SameSite lo trattiene sulle richieste cross-site (blocca il CSRF); e il prefisso di nome __Host- lo vincola a una sola origine.
Qual è il timeout di sessione corretto?
Due orologi, entrambi imposti dal server: un timeout di inattività – pochi minuti per le applicazioni di alto valore, 15–30 per i casi comuni – e un timeout assoluto di poche ore, indipendente dall'attività. Le linee guida federali sull'identità digitale, al loro secondo livello di assurance, raccomandano al massimo 1 ora di inattività e una riautenticazione almeno ogni 24 ore.
Come deve funzionare il logout?
Prima lato server: va distrutto il record di sessione perché l'ID muoia in ogni punto, e solo dopo si cancella il cookie. Il fallimento classico è l'inverso – eliminare il solo cookie lascia la sessione viva per chiunque abbia catturato l'ID, riducendo il "logout" a un'animazione di interfaccia.
Il "ricordami" è sicuro?
È uno scambio deliberato di sicurezza in cambio di comodità. Fatto con criterio: un token distinto a lunga durata, monouso e ruotato a ogni visita, conservato in un cookie irrobustito, revocabile lato server, invalidato al cambio password – e mai un sostituto della riautenticazione prima di un'azione sensibile.