Computer quantistici: siamo davvero alla vigilia del grande salto?
9 – Gestione Sessioni e Cookie
Capire la differenza tra sessioni e cookie, imparare a creare e gestire sessioni in PHP, usare cookie per persistenza lato client, e mettere in pratica il tutto con un esercizio: implementare un carrello e-commerce semplificato.
Cookie
Piccoli file (coppie chiave/valore) memorizzati dal browser sul computer dell’utente.
Sono inviati automaticamente al server ad ogni richiesta verso il dominio che li ha impostati.
Sono utili per persistenza lato client: preferenze tema, tracking, ricordami.
Limitazioni: dimensione limitata (~4 KB per cookie, limite totale per dominio variabile), visibili al client (quindi sensibili al furto/modifica se non protetti).
Sessione
Dati memorizzati sul server associati a un identificatore (session id) che il client porta con sé, solitamente tramite un cookie di sessione.
Il server mantiene lo stato (es. dati di login, carrello) e il client contiene solo l’ID.
Vantaggi: i dati effettivi non sono memorizzati nel browser, maggior sicurezza e possibilità di memorizzare strutture dati complesse.
Svantaggi: consumo di risorse server, necessità di gestione della scadenza e di storage scalabile in ambienti distribuiti.
Sintesi: cookie = memoria lato client, sessione = memoria lato server + riferimento lato client.
Il server crea una sessione quando necessario e genera un identificatore unico (session id).
Al client viene inviato (di solito) un cookie contenente il session id.
Ad ogni richiesta successiva il browser invia quel cookie; il server usa il session id per recuperare i dati della sessione (array, oggetti, ecc.).
Quando l’utente effettua il logout o la sessione scade, il server distrugge i dati associati a quell’id.
Elementi pratici da conoscere:
session_start() (o equivalente) apre/ristabilisce la sessione.
Recupero/assegnazione: la sessione è generalmente rappresentata da un array associativo lato server (es. $_SESSION).
Terminazione: si devono fornire funzioni per distruggere la sessione in modo sicuro (session_unset() + session_destroy() e rimozione cookie di sessione).
Quando si imposta un cookie bisogna considerare:
nome e valore (entità chiave/valore).
durata (expire): tempo dopo il quale il cookie viene eliminato (session cookie = scade alla chiusura del browser).
path e domain: limitano dove il cookie è valido.
secure: se impostato, il cookie viene inviato solo tramite connessioni HTTPS.
HttpOnly: se impostato, il cookie non è accessibile via script JavaScript (riduce rischio XSS).
SameSite: controlla l’invio del cookie in contesti cross-site (Lax, Strict, None + Secure).
Buone pratiche:
Non mettere dati sensibili non cifrati nei cookie. Se devi memorizzare info sensibili, usa cookie come token che fa riferimento a dati server-side.
Impostare HttpOnly e Secure quando possibile.
Usare SameSite per mitigare CSRF (Cross-Site Request Forgery).
Rischi principali:
Session fixation: un attaccante fornisce un session id noto alla vittima e poi sfrutta la sessione autenticata.
Mitigazione: rigenerare il session id dopo login (es. session_regenerate_id(true)).
Session hijacking: furto del session id (es. via XSS o rete non cifrata).
Mitigazione: usare HTTPS, cookie HttpOnly, limitare durata sessione, associare sessione a IP o user agent con attenzione (può causare falsi positivi).
Scadenza e pulizia: definire timeout di inattività e rimuovere dati obsoleti.
Storage lato server: sessioni per siti con più server richiedono storage condiviso (file system condiviso, database, Redis/Memcached). Evitare dipendere solo dal file system locale in cluster.
Best practice operative:
Chiamare sempre la funzione di avvio della sessione in testa alla pagina prima di qualsiasi output.
Rigenerare l’id dopo l’autenticazione e in situazioni sensibili.
Limitare lo scope e la durata della sessione.
Distruggere la sessione al logout e cancellare il cookie di sessione.
Esempi di come si possono organizzare i dati lato sessione (concetto, non codice):
Utente loggato:
session['user'] = { id: 42, username: 'mario', roles: ['user'] }
session['last_activity'] = 2025-09-21T11:00:00Z
Carrello (esempio):
session['cart'] = { product_id => { qty: 2, price: 9.90 }, ... }
Totali calcolati al volo dal server leggendo session['cart'].
Token CSRF:
session['csrf_token'] = 'random-string' per verificare i POST provenienti dal form.
Flusso utente:
Utente visita sito — il server avvia/chiama la sessione.
Quando l’utente aggiunge un prodotto al carrello, il server aggiorna session['cart'] (incrementa quantità, aggiunge prodotto).
Nel checkout, il server calcola totali, imposte, spedizione leggendo la sessione; dopo pagamento finale, si può svuotare la sessione o mantenerne una parte per storico.
Se l’utente non è loggato, la sessione tiene lo stato del carrello. Se successivamente effettua il login, si può fondere il carrello della sessione con quello salvato nel DB (merge).
Esempio di struttura (valori d’esempio):
session['cart'] = { 101: { name: "T-shirt", qty: 2, price: 15.00 }, 204: { name: "Cappello", qty: 1, price: 12.50 } }
Totale calcolato: (2 * 15.00) + (1 * 12.50) = 42.50
Obiettivo: descrivere la logica completa senza mescolare codice, così da poterla implementare facilmente.
Aggiungere prodotto al carrello.
Rimuovere prodotto o decrementare quantità.
Visualizzare il carrello con voci, quantità e subtotali.
Svuotare il carrello al completamento dell’ordine.
Conservare il carrello tra le pagine usando sessione.
session['cart'] mappa product_id → oggetto { qty, unit_price, name }.
Aggiungi prodotto
Ricevo product_id, qty (default 1).
Se product_id già presente in session['cart'], incremento qty.
Altrimenti aggiungo nuova voce con qty e unit_price preso dal catalogo.
Aggiorno session['last_update'] = now.
Rimuovi prodotto
Ricevo product_id.
Se presente in session['cart'] rimuovo la voce o decremento la qty se richiesto.
Visualizza carrello
Itero su session['cart'], calcolo subtotal per voce = qty * unit_price.
Sommo i subtotali per ottenere cart_total.
Mostro cart_total, numero di articoli (somma delle quantità) e dettagli delle voci.
Checkout
Verifico che il carrello non sia vuoto.
Applico controlli (disponibilità, prezzi correnti, sconti).
Se tutto ok, creo l’ordine nel database e svuoto il carrello in sessione (oppure lo salvo nello storico dell’utente).
Azione: aggiungi product_id = 101 (T-shirt, unit_price = 15.00), qty = 2.
session['cart'] diventa {101: {qty:2, unit_price:15.00, name:"T-shirt"}}.
Azione: aggiungi product_id = 204 (Cappello, unit_price = 12.50), qty = 1.
session['cart'] ora contiene 2 voci.
Visualizza carrello:
Voce 101: subtotal = 2 * 15.00 = 30.00
Voce 204: subtotal = 1 * 12.50 = 12.50
Totale carrello = 42.50
Sempre ricalcolare i prezzi dal catalogo al momento del checkout (evitare di fidarsi solo del valore in sessione).
Usare token CSRF per proteggere azioni POST (aggiungi/rimuovi).
Consentire agli utenti autenticati di salvare il carrello nel database per ripristino futuro su altri device.
Sessione non inizializzata: chiamare la funzione di avvio della sessione prima di leggere/scrivere dati.
Output prima della session_start(): l’invio di output prima della definizione dei cookie o dell’avvio della sessione impedisce la corretta impostazione del cookie di sessione (headers already sent).
Dimenticare di rigenerare l’ID dopo il login → rischio session fixation.
Non chiudere / non distruggere la sessione al logout → rischio che una macchina condivisa mantenga una sessione attiva.
Dipendenza dallo storage locale su cluster → sessioni non condivise tra nodi (usare storage condiviso come Redis).
Per debug:
Loggare session_id() e il contenuto di session (in ambiente di sviluppo) per verificare flusso stato.
Verificare cookie nel browser (devtools → Application / Storage) per controllare scadenze e flag.
Qual è la differenza fondamentale tra cookie e sessione?
Risposta: cookie = dati memorizzati nel browser (lato client); sessione = dati memorizzati sul server associati a un session id trasportato dal client.
Perché rigenerare l’id di sessione dopo il login?
Risposta: per mitigare session fixation; garantire che un id precedente non utilizzabile dall’attaccante rimanga valido dopo autenticazione.
Quali flag di cookie aumentano la sicurezza?
Risposta: HttpOnly, Secure, e SameSite (insieme aiutano a ridurre i rischi XSS/CSRF e furto su connessioni non TLS).
Dove conviene memorizzare sessioni in un ambiente con più server?
Risposta: in uno storage condiviso (Redis, Memcached, DB o filesystem condiviso) per rendere le sessioni accessibili da tutti i nodi.
Persistenza cross-device: salvare carrelli di utenti autenticati nel DB e fare merge con quello in sessione.
Utilizzare JWT (JSON Web Token) per autenticazione stateless quando appropriato (diverso modello rispetto a sessioni server-side).
Implementare limitazione della durata della sessione e logout automatico per inattività.
Monitorare e invalidare sessioni sospette (es. cambio IP frequente o attività anomale).
Commenti
Posta un commento