Cookie

Il protocollo HTTP è per sua natura stateless, questo significa che non c'è continuità tra una richiesta e l'altra, non c'è un contesto mantenuto dal server e il server non ha idea del fatto che sia lo stesso client a eseguire le due richieste una in fila all'altra. In altre parole, ogni richiesta viene trattata come indipendente da tutte le altre dal server. Inoltre senza avere una gestione delle sessioni bisognerebbe inviare, per ogni richiesta, le credenziali per autenticarsi all'applicazione web, il che renderebbe tutta la gestione molto più complicata.

Il meccanismo dei cookies è una delle soluzioni comuni per mantenere delle informazioni di stato durante richieste diverse.

I cookie sono memorizzati dal client (quindi dal browser) ma vengono creati dal server, che li comunica al client nelle risposte HTTP. Questo meccanismo è implementato attraverso l'header di risposta Set-Cookie:

HTTP/1.1 200 OK
Host: localhost:8080
Connection: close
X-Powered-By: PHP/8.2.10-2ubuntu2.1
Set-Cookie: PHPSESSID=2d9gohs4islqtk25m3jp9rcnh9; path=/
Content-type: text/html; charset=UTF-8

Nella risposta precedente possiamo notare come la presenza dell'header Set-Cookie istruisca il browser a memorizzare il cookie di nome PHPSESSID, di valore 2d9gohs4islqtk25m3jp9rcnh9 e inoltre specifica il percorso dal quale quel cookie ha valore: /.

Cookies header

Una volta che il browser ha memorizzato il cookie esso verrà inviato al server, nelle richieste verso lo stesso dominio:

GET /index.php HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.2.1
Cookie: PHPSESSID=2d9gohs4islqtk25m3jp9rcnh9

Come si può notare dalla richiesta il cookie viene inviato all'interno della richiesta tramite l'header Cookie, inoltre notiamo che vengono inviati solo il nome del cookie e il suo valore. Gli altri attributi rimangono solo memorizzati sul client e servono al browser a capire in quali casi inserire i cookie nelle richieste.

I cookie possono avere vari attributi, alcuni dei più utili sono:

  • Expires: indica la data di scadenza del cookie, quando questa data è passata il browser dovrebbe cancellare questo cookie dalla memoria, o comunque non inviarlo più nelle richieste.
  • Max-Age: indica un periodo, in secondi, per il quale il cookie è valido. Il periodo inizia dal momento in cui il client riceve questo cookie e una volta passato questo tempo, andrebbe cancellato. Esistono due modi diversi per specificare la scadenza perché Max-Age risolve il problema di orari diversi tra client e server.
  • Domain: indica il dominio sul quale i cookie devono essere inviati dal browser, se viene specificato implica che il browser invierà questi cookie su tutti gli endpoint di quel dominio, e anche sui sottodomini. Non si può specificare un dominio diverso da quello che sta emettendo il cookie.
  • Path: indica il percorso sul server per la quale inviare i cookie, è valido anche per tutti i percorsi sotto quella specificata. Può essere usato per ospitare applicazioni diverse in diversi percorsi del server, ma mantenendo comunque un isolamento dei cookie.

Ci sono altri attributi possibili, in particolare alcuni offrono alcune funzionalità che possono essere di aiuto per aumentare la sicurezza del proprio applicativo web. Per una lista più completa si consiglia di leggere la documentazione di MDN, di alcuni di questi parleremo nei prossimi capitoli.

Dato che i cookie possono essere utilizzati per legare varie richieste una all'altra, e per correlarle con l'utente che le sta eseguendo, è nato il concetto di cookie di sessione. Un cookie di sessione è un particolare cookie che identifica un utente una volta che esso si è autenticato presso il servizio. Il server tiene in memoria una corrispondenza tra questo cookie di sessione, che è spesso una stringa casuale, e i dati associati all'utente. In questo modo ogni volta che l'utente esegue una richiesta e invia anche il cookie di sessione, il server può trattare quella richiesta come autenticata e richiesta dall'utente.

Dato che i cookie vengono inviati dal client verso il server devono essere trattati come input utente, pertanto vanno sanitizzati prima di essere usati per qualsiasi cosa e non sono da considerarsi fidati. Alcune soluzioni a questo problema prevedono l'utilizzo di meccanismi di controllo d'integrità, come ad esempio i ViewState di ASP.NET o i JWT.