Come funziona questo controllo
Scanaris legge gli header Set-Cookie che il tuo server invia caricando la pagina principale e controlla gli attributi di ogni cookie. Verifica tre cose: che abbia Secure (richiesto solo se il sito va su HTTPS), che abbia HttpOnly e che dichiari SameSite. Se il nome del cookie suggerisce sessione o autenticazione (session, auth, token, sid e simili), il riscontro è di severità media; altrimenti bassa. C'è un caso speciale con severità media propria: SameSite=None senza Secure, che i browser moderni rifiutano direttamente, per cui il cookie non funziona e in più tradisce una configurazione pensata per l'uso tra siti. Si vedono solo i cookie inviati in quella prima risposta; quelli creati dopo il login si verificano meglio con il comando qui sotto o con la scansione autenticata.
Cosa significa ogni attributo
- Secure: il cookie viaggia solo su HTTPS. Senza, una richiesta su HTTP (un vecchio link, una rete pubblica) lo invia in chiaro e chiunque sulla rete lo legge.
- HttpOnly: JavaScript non può leggerlo. È la differenza tra un XSS che ruba la sessione e uno che non può.
- SameSite: quando viene inviato da un altro sito.
Laxlo invia nelle navigazioni normali ma non nelle richieste avviate da un altro sito;Strictmai dall'esterno;Nonesempre, e richiedeSecure. È la difesa principale contro il CSRF.
Cosa fa un attaccante con un cookie di sessione senza questi attributi
Senza HttpOnly, qualsiasi script iniettato legge document.cookie, invia il valore al suo server ed entra con la tua sessione. Senza SameSite, una pagina altrui può inviare un form al tuo sito con il cookie allegato e fare un acquisto o cambiare un'email a nome dell'utente. Senza Secure, basta che l'utente apra un link http:// verso il tuo dominio su una rete condivisa. In tutti e tre i casi il risultato è lo stesso: qualcuno agisce come il tuo utente.
Come sistemarlo a seconda del tuo framework
// Express con express-session
app.use(session({
cookie: { secure: true, httpOnly: true, sameSite: 'lax' }
}));
// Next.js (Route Handler o Server Action)
cookies().set('session', value, { httpOnly: true, secure: true, sameSite: 'lax', path: '/' });
// Nuxt (server/api)
setCookie(event, 'session', value, { httpOnly: true, secure: true, sameSite: 'lax', path: '/' });
Con Supabase in un'app con server, la libreria @supabase/ssr salva la sessione in cookie con questi attributi; in una SPA pura la sessione va in localStorage, che è ciò che misura il controllo token nello storage. In Django, Rails o Laravel gli attributi si configurano nelle impostazioni di sessione e sono ragionevoli di default; controlla che nessuno li abbia abbassati per "risolvere" un problema di sviluppo.
Verifica che sia sistemato
curl -sI https://tuodominio.com | grep -i "set-cookie"
curl -sI -X POST https://tuodominio.com/api/login -d "..." | grep -i "set-cookie"
Ogni cookie di sessione deve mostrare Secure; HttpOnly; SameSite=Lax (o Strict). Se il tuo login è un form, guarda la risposta negli strumenti del browser, scheda Rete, header di risposta.
Domande frequenti
Il mio cookie lo crea JavaScript (analytics, preferenze). Non può essere HttpOnly.
Corretto, e non è un problema: quei cookie non danno accesso a nulla. Il controllo lo segnala con severità bassa per l'attributo mancante; ciò che conta è che quelli di sessione ce l'abbiano.
Ho bisogno di SameSite=None perché la mia app gira in un iframe su un altro dominio.
Allora è legittimo, sempre con Secure. Assicurati che le altre difese contro il CSRF (token nei form, controllo dell'Origin) siano attive, perché SameSite non ti protegge più.
Lax o Strict?
Lax per la maggior parte dei casi: mantiene la sessione quando l'utente arriva da un link esterno. Strict se il cookie dà accesso a qualcosa di molto sensibile e accetti che l'utente debba rientrare arrivando dall'esterno.