modulo 08 / lezione 41
Debugging di dati, backend e integrazioni
Autenticazione, sessioni, JWT e CORS
Distinguere errori di identità, permessi, cookie (SameSite, Secure, HttpOnly), token JWT (firma, scadenza, audience), CORS preflight OPTIONS.
In parole semplici
Gli errori di sicurezza si nascondono dietro sintomi identici: “non funziona”. Sapere distinguere identità (chi sei), autorizzazione (cosa puoi fare), sessione (come ti ricordo), CORS (da dove vieni) trasforma un’ora di indagine in dieci minuti di lettura mirata.
Parole nuove
- autenticazione: chi sei (login).
- autorizzazione: cosa puoi fare (permessi).
- sessione: meccanismo con cui il server ti riconosce su richieste successive.
- cookie: piccolo dato che il browser invia automaticamente.
- JWT (JSON Web Token): token firmato che contiene informazioni utente.
- CORS: meccanismo che limita richieste cross-origin.
Cosa impari
- Distinguere 401 da 403 (di nuovo, perché ci si casca sempre).
- Leggere cookie con
SameSite,Secure,HttpOnly. - Capire payload e claim JWT.
- Risolvere errori CORS più frequenti.
401 vs 403 (ancora)
- 401 Unauthorized = “Non so chi sei”. Il token manca, è scaduto, è invalido.
- 403 Forbidden = “So chi sei, ma non puoi”. Il ruolo non ha permessi.
Sbagliare l’interpretazione porta a fix sbagliati (rinnovi token quando il problema sono i permessi, o viceversa).
Cookie e flag
Set-Cookie: session=abc123; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
Flag:
- HttpOnly: il cookie non è leggibile da JavaScript. Protezione da XSS. Per token di sessione, obbligatorio.
- Secure: il cookie viaggia solo su HTTPS. Mai usare in
localhostHTTP senza eccezioni. - SameSite: limita l’invio cross-origin.
Strict: cookie inviato solo da richieste same-site.Lax: inviato per navigazioni top-level (cliccare un link).None: inviato sempre, ma richiedeSecure.
Bug tipici:
- Login funziona, ma su pagine successive l’utente è “scollegato”: probabile
SameSite=Strictsu redirect da OAuth. - Cookie non parte da app embeddata in iframe: serve
SameSite=None; Secure. - Cookie in dev locale non funziona:
Securesuhttp://localhostè ignorato in alcuni browser.
JWT: cos’è e come si legge
Tre parti separate da .:
eyJhbGc...header...eyJzdWI...payload...XYZ...signature
Decoding (base64url):
const payload = JSON.parse(atob(token.split(".")[1]));
console.log(payload);
// {
// "sub": "user-42",
// "name": "Carlo",
// "iat": 1735603200,
// "exp": 1735606800,
// "aud": "my-app",
// "iss": "auth.example.com"
// }
Claim standard:
- sub: subject (id utente).
- iat: issued at (timestamp emissione).
- exp: expiration (timestamp scadenza).
- aud: audience (per chi è).
- iss: issuer (chi ha emesso).
Diagnosi:
- Token scaduto →
exp < now()→ 401. - Audience sbagliato →
audnon corrisponde → 401 o 403. - Firma invalida → 401.
Strumento utile: jwt.io (decodifica visiva). Attenzione: incolla solo token di test, mai produzione.
Storage del token: dove?
- HttpOnly cookie: il più sicuro (XSS non lo legge). Server-driven.
- localStorage: vulnerabile a XSS. Sconsigliato per token sensibili.
- memory (variabile JS): sicuro contro XSS persistente, ma si perde a refresh.
Bug: token in localStorage, attacco XSS, attaccante esfiltra. Bug grave di sicurezza, non solo funzionale.
CORS: la quasi-magia
Browser blocca richieste cross-origin per JavaScript:
- Stesso origin = stesso schema + host + porta.
https://app.example.com:443ehttps://api.example.com:443= origin diversi.
Per consentire cross-origin, il server risponde con header CORS:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Preflight OPTIONS
Per richieste “non semplici” (es. con Content-Type: application/json, header custom), il browser fa una richiesta OPTIONS prima:
OPTIONS /api/utenti HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
Il server risponde con gli header Allow-*. Solo se ok, parte la richiesta vera.
Errori frequenti:
OPTIONSritorna 404 → il server non gestisce preflight.Allow-Origin: *conAllow-Credentials: true→ vietato dalla spec.Allow-Originnon corrisponde all’origine del browser → bloccato.
Errori CORS in console
Access to fetch at 'https://api.x.com/...' from origin 'https://app.y.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Diagnosi:
- È una preflight che fallisce? Network mostra
OPTIONScon 4xx. - È la richiesta vera? Vedi header di risposta.
- Manca un header? Aggiungi lato server.
Importante: CORS è enforcement del browser. Da curl la richiesta funziona, ma dal browser no. Sintomo classico.
Esercizio guidato
- Apri un sito che richiede login. Cattura la response di login.
- Vedi
Set-Cookie: quali flag ci sono? Apri Application → Cookies per ispezionare. - Cerca un endpoint protetto: vedi quali header parte (Cookie, Authorization).
- Decodifica un JWT (anche di test, mai dati reali) e identifica
exp,aud,iss. - Provoca un errore CORS: prova a chiamare un’API esterna da console (senza CORS abilitato).
Errori frequenti del principiante
- Mettere il token in
localStoragesenza valutare XSS. Allow-Origin: *in produzione.- Confondere autenticazione con autorizzazione. Login non = permessi.
- Ignorare
exp. Token scaduto sembra “bug random” finché non lo decodifichi.