Caching, autenticazione, tipi MIME e URI in HTTP
In questa pagina 7
Questa nota raccoglie quattro meccanismi di HTTP che un server o un client reale implementano subito dopo il protocollo base (HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encodingHTTP/1.1 (oggi RFC 9110 e 9112) rende la connessione persistente di default (si chiude solo con "Connection: close"), rende obbligatorio l'header Host (virtual hosting) e introduce i nuovi metodi PUT, DELETE, OPTIONS, TRACE, Expect: 100-continue, richieste di intervalli (206) e Transfer-Encoding: chunked; con la connessione persistente il client deve sapere dove finisce ogni risposta: lunghezza del corpo nell'ordine HEAD/1xx/204/304 senza corpo, Transfer-Encoding chunked, Content-Length, altrimenti fino alla chiusura; il chunked divide il corpo in blocchi preceduti dalla lunghezza in esadecimale, termina con un chunk 0 e un trailer facoltativo, e si decodifica contando i byte dichiarati (non cercando CRLF).HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encoding →): la cache, l'autenticazione, i tipi MIME e gli URI. I riferimenti normativi sono RFC 9110 (semantica), RFC 9111 (caching), RFC 7617 e 7616 (autenticazione Basic e Digest), RFC 2045-2046 (MIME), RFC 3986 (URI).
La cache HTTP
Una cache conserva una copia delle risposte per riusarla al posto di contattare di nuovo il server. Riduce il numero di richieste, i tempi di caricamento percepiti e il traffico. Ce ne sono di due tipi:
Una cache memorizza di norma le risposte a GET (e HEAD) con codici come 200, 301, 404. La chiave è metodo più URI, a cui si aggiungono gli header elencati in Vary. Le risposte alle POST e quelle con Cache-Control: no-store non si riusano.
Freschezza
Una risposta memorizzata è fresca finché la sua età è minore della sua durata di freschezza. Finché è fresca la cache la serve senza contattare il server. La durata si ricava, in quest'ordine:
- dalla direttiva
Cache-Control: max-age=N(secondi di vita dalla generazione della risposta;s-maxagevale per le sole cache condivise); - dall'header
Expires(una data assoluta, formatoSun, 06 Nov 1994 08:49:37 GMT); - altrimenti da un'euristica: se c'è
Last-Modifieduna cache può usare circa il 10% del tempo trascorso fraLast-ModifiedeDate(RFC 9111 par. 4.2.2).
L'età si calcola dalla data di generazione (Date) e dall'header Age che le cache intermedie aggiungono con i secondi già passati nella loro cache. Esempio. Risposta con Date: 10:00:00 e Cache-Control: max-age=3600: alle 10:30 è fresca (età 1800 s < 3600) e viene riusata senza richieste; alle 11:05 (età 3900 s) è scaduta (stale) e va rivalidata. Esempio con l'euristica: un file modificato 10 giorni prima senza max-age né Expires può essere considerato fresco per circa 1 giorno.
Rivalidazione
Quando la copia è scaduta non si butta via: si chiede al server se è ancora buona, con una richiesta condizionale. Servono dei validatori, che il server manda nella risposta originale:
| validatore (risposta) | header condizionale (richiesta successiva) | significato |
|---|---|---|
Last-Modified: <data> |
If-Modified-Since: <data> |
"mandami il corpo solo se è cambiato dopo questa data" |
ETag: "abc123" |
If-None-Match: "abc123" |
"mandami il corpo solo se la versione non è abc123" |
L'ETag (entity tag) è un identificatore opaco della versione della risorsa (di solito un hash del contenuto, oppure data e dimensione del file), scritto fra virgolette; con il prefisso W/ (W/"abc123") è un validatore debole (stesso significato, non necessariamente stessi byte). Rispetto alla data ha due vantaggi: ha una risoluzione migliore del secondo e funziona anche se la data di modifica non è affidabile.
GET /logo.png HTTP/1.1
Host: www.example.com
If-None-Match: "abc123"Se la versione corrente ha ancora quel ETag, il server risponde:
HTTP/1.1 304 Not Modified
ETag: "abc123"
Cache-Control: max-age=3600Il 304 non ha corpo: la cache riusa la copia memorizzata e riparte con una nuova durata di freschezza (dagli header del 304). Il risparmio è tutto il trasferimento del corpo; resta un viaggio di andata e ritorno. Se la risorsa è cambiata il server risponde 200 con il nuovo corpo, il nuovo ETag e il nuovo Last-Modified.
t = 0 GET /logo.png -> 200, ETag "abc123", max-age=3600, corpo (si memorizza)
t = 1800 s GET /logo.png -> servita dalla cache, nessun pacchetto in rete (fresca)
t = 3700 s GET /logo.png + If-None-Match: "abc123" -> 304 Not Modified (si rinnova la freschezza)
più tardi (logo cambiato) If-None-Match: "abc123" -> 200, ETag "def456", corpo nuovoLa stessa logica serve a evitare i lost update: If-Match: "abc123" in una PUT o DELETE fa eseguire l'operazione solo se la versione corrente è quella letta dal client; altrimenti il server risponde 412 Precondition Failed.
Cache-Control
L'header Cache-Control controlla la cache, in risposta (per il server) e in richiesta (per il client):
| direttiva | dove | effetto |
|---|---|---|
max-age=N |
risposta | fresca per N secondi; max-age=0 = subito scaduta |
s-maxage=N |
risposta | come max-age ma solo per le cache condivise |
public |
risposta | può essere memorizzata anche da cache condivise |
private |
risposta | solo la cache privata dell'utente (non i proxy): per risposte personalizzate |
no-cache |
risposta | si può memorizzare ma va rivalidata prima di ogni uso |
no-store |
risposta | non memorizzare affatto (dati sensibili) |
must-revalidate |
risposta | dopo la scadenza, vietato usare la copia senza rivalidare (neanche se il server è irraggiungibile) |
no-cache, max-age=0 |
richiesta | il client vuole una risposta rivalidata (ricarica) |
Attenzione al nome: no-cache non vieta la cache, impone la rivalidazione; il divieto è no-store. Pragma: no-cache è l'equivalente di HTTP/1.0, obsoleto. Un'altra intestazione è Vary: Accept-Encoding: dice che la risposta dipende da quell'header di richiesta, quindi la cache deve tenere copie diverse per valori diversi (versione compressa e non). Un browser, alla pressione di F5, manda richieste condizionali; a Ctrl+F5 bypassa la cache.
Un server che implementa la cache deve quindi (1) generare ETag e/o Last-Modified, (2) rispondere 304 quando il validatore combacia, (3) scegliere una politica con Cache-Control (Esercizio - Server con autenticazione Basic, ETag e GET condizionale (sul modello della prova pratica)); un client che implementa la cache (come quello di Esercizio - GET condizionale con If-Modified-Since e cache su file (slide HTTP 0.9 e 1.0)) memorizza corpo e validatore e li usa nella richiesta successiva.
Autenticazione
HTTP ha un meccanismo generale di sfida e risposta (RFC 9110 par. 11):
- Il client chiede una risorsa protetta senza credenziali.
- Il server risponde
401 Unauthorizedcon l'headerWWW-Authenticate, che indica lo schema e un realm (l'"area protetta"). - Il client ripete la richiesta con l'header
Authorization, che contiene le credenziali nel formato dello schema. - Se vanno bene:
200; altrimenti di nuovo401. Un403 Forbiddensignifica invece "ho capito chi sei, ma non hai diritto".
Per i proxy lo schema è lo stesso con altri nomi: 407 Proxy Authentication Required, Proxy-Authenticate, Proxy-Authorization.
Basic
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Area riservata", charset="UTF-8"GET /private/riservato.txt HTTP/1.1
Host: www.example.com
Authorization: Basic bWFyaW86c2VncmV0bw==La credenziale è base64("utente:password"). Per mario:segreto la codifica Base64 (WebSocket, QUIC e HTTP-3HTTP e' richiesta e risposta, quindi poco adatto a notifiche e dati in tempo reale (polling, long polling, SSE); WebSocket (RFC 6455) apre con un handshake HTTP/1.1 Upgrade (Sec-WebSocket-Key a 16 byte casuali in Base64, risposta 101 con Sec-WebSocket-Accept = Base64 di SHA-1 di chiave piu' GUID fisso) un canale bidirezionale persistente sulla stessa connessione TCP, con frame di 2-14 byte di intestazione (FIN, opcode, MASK, lunghezza su 7, 16 o 64 bit, chiave di mascheramento obbligatoria dal client al server) e messaggi di testo, binari, close, ping e pong. QUIC (RFC 9000) e' un protocollo di trasporto sopra UDP con TLS 1.3 integrato, flussi indipendenti (niente head-of-line blocking fra flussi), connection ID che permettono di cambiare rete, handshake in 1 RTT e ripresa in 0 RTT; HTTP/3 (RFC 9114) mappa HTTP su QUIC con un flusso per richiesta e QPACK per gli header, ed e' annunciato con Alt-Svc.WebSocket, QUIC e HTTP-3 → riprende l'algoritmo) è bWFyaW86c2VncmV0bw==; l'esempio della RFC 7617 è Aladdin:open sesame, cioè QWxhZGRpbjpvcGVuIHNlc2FtZQ==. Il nome utente non può contenere : (il primo : separa i due campi).
Basic non cifra niente: Base64 è una codifica, non una protezione, e si inverte in un attimo. Va quindi usato solo sopra TLS (HTTPS). Il browser rimanda le credenziali a ogni richiesta successiva dello stesso realm (HTTP è senza stato): per questo conviene non usarlo per sessioni lunghe e comparare le password con funzioni a tempo costante.
Digest
Digest (RFC 7616) evita di trasmettere la password: il client trasmette un hash. Nella sfida il server manda un nonce (numero casuale usato una volta), un realm, qop="auth" e l'algoritmo; il client calcola (con MD5 o, meglio, SHA-256):
HA1 = H( utente : realm : password )
HA2 = H( metodo : uri )
response = H( HA1 : nonce : nc : cnonce : qop : HA2 )dove nc è un contatore delle richieste con quel nonce e cnonce un numero scelto dal client (contro gli attacchi con testi in chiaro scelti). Esempio verificato (RFC 2617, MD5): utente Mufasa, realm testrealm@host.com, password Circle Of Life, nonce dcd98b7102dd2f0e8b11d0f600bfb0c093, GET /dir/index.html, nc=00000001, cnonce=0a4f113b, qop=auth: HA1 = 939e7578ed9e3c518a452acee763bce9, HA2 = 39aff3a2bab6126f332b942af96d3366 e response = 6629fae49393a05397450978507c4ef1. La password non viaggia, ma il server deve poter ricostruire HA1 (non può conservare solo un hash lento della password) e MD5 oggi è debole: in pratica Digest è poco usato.
Altri schemi: Bearer (RFC 6750), con un token ottenuto da un servizio di autorizzazione (OAuth 2.0), e le sessioni con cookie (Livello applicazione - HTTPIl livello applicazione è il più alto della pila: offre servizi all'utente con una connessione logica tra le due applicazioni e riceve servizi solo dal trasporto (DNS, HTTP, e-mail, FTP). Il Web (WWW, nato al CERN nel 1989) è un servizio client-server distribuito di pagine collegate da ipertesti; ogni pagina ha un URL protocollo://host:porta/percorso. HTTP: il client manda una richiesta, il server una risposta, su TCP (server sulla porta 80, client su una porta temporanea); senza stato. Messaggi di testo (riga di richiesta o di stato, intestazioni, riga vuota, corpo), metodi GET, POST, HEAD, PUT, DELETE, codici di stato 2xx-5xx. Una pagina con N oggetti incorporati richiede 2(N+1) RTT con connessioni non persistenti e (N+2) RTT con connessione persistente (trascurando la trasmissione). I cookie danno memoria al protocollo: Set-Cookie nella risposta, Cookie nelle richieste, file nel browser e base di dati nel sito. Un proxy (web cache) tiene le copie delle risposte recenti: meno carico sul server, meno traffico, meno ritardo.Livello applicazione - HTTP →); entrambi, come Basic, vanno protetti con TLS (Crittografia asimmetrica, RSA e TLSCrittografia asimmetrica (a chiave pubblica): chiave di cifratura pubblica v_B, chiave di decifratura privata s_B, matematicamente legate; C = E_vB(P), P = D_sB(C); dà riservatezza. I certificati digitali, emessi da una Certificate Authority e firmati con la sua chiave privata, legano un'identità a una chiave pubblica. Firma digitale: hash del messaggio cifrato con la chiave privata; garantisce autenticità, integrità e non ripudio. RSA: si scelgono due primi grandi p e q, N = pq, phi(N) = (p-1)(q-1), e coprimo con phi(N), d = e^(-1) mod phi(N); chiave pubblica (N, e), segreta (N, d); cifratura c = m^e mod N, decifratura m = c^d mod N con m < N (teorema di Eulero); sicura finché la fattorizzazione è difficile (N di almeno 2048 bit); il padding casuale (PKCS#1 v1.5: 00 02 [casuale] 00 [m]) difende da malleabilità e determinismo. La firma RSA è s = m^d mod N, verificata con s^e mod N. TLS (su TCP) autentica gli estremi con il certificato, cifra i dati con una chiave di sessione simmetrica e garantisce l'integrità con i MAC; da TLS 1.0 a 1.3 la chiave si ricava con Diffie-Hellman e l'handshake si accorcia. DTLS è la versione per UDP.Crittografia asimmetrica, RSA e TLS →).
Una nota per le cache: una risposta a una richiesta con Authorization non può essere servita da una cache condivisa ad altri utenti, salvo che sia dichiarata public.
Tipi MIME
Ogni risposta che ha un corpo dice che tipo di dati contiene, con Content-Type. Il formato è lo standard MIME (nato per la posta, RFC 2045-2046; Posta elettronica - SMTP, POP3 e IMAPLa posta elettronica è una transazione a senso unico: non ha senso che il destinatario tenga un server sempre acceso, quindi si usano server intermedi. Servono due User Agent (UA, il programma dell'utente), due programmi client/server di spinta (MTA, protocollo SMTP: mittente-suo server e server-server) e un programma client/server di tiro (MAA, POP3 o IMAP4: server del destinatario-destinatario). SMTP usa TCP porta 25, comandi HELO, MAIL FROM, RCPT TO, DATA, QUIT e risposte a tre cifre (220 pronto, 250 ok, 354 inizia il testo, 221 chiusura, 421 non disponibile) in tre fasi: apertura, trasferimento, chiusura. POP3 (porta 110): utente e password, poi elenca e scarica i messaggi uno a uno; non organizza la posta sul server. IMAP4 aggiunge intestazioni prima del download, ricerca, download parziale, cartelle sul server. MIME permette di spedire dati non ASCII (immagini, video, lettere accentate) traducendoli in ASCII a 7 bit, per esempio in base64 (3 byte diventano 4 caratteri).Posta elettronica - SMTP, POP3 e IMAP →):
Definizione (media type).
tipo/sottotipo[; parametro=valore]. Il tipo indica la famiglia (text,image,audio,video,application,multipart), il sottotipo il formato preciso. I valori sono registrati presso IANA e non distinguono maiuscole e minuscole.
Il parametro charset dice la codifica dei caratteri dei testi (utf-8). Il server ricava il tipo dall'estensione del file con una tabella: è la funzione mime_type degli esercizi (Esercizio - Server HTTP iterativo con GET, HEAD e codici di errore (sul modello della prova pratica)). Un tipo sbagliato fa mostrare male la risorsa (un CSS servito come text/plain non viene applicato) o permette attacchi di content sniffing, mitigati da X-Content-Type-Options: nosniff.
Moduli e multipart
Un modulo HTML invia i campi in due formati:
application/x-www-form-urlencoded: coppienome=valoreseparate da&, con percent-encoding (lo spazio diventa+oppure%20);multipart/form-data: il corpo è diviso in parti separate da una stringaboundarydichiarata nelContent-Type; ogni parte ha i propri header e può contenere un file. Le righe di separazione sono--boundarye la chiusura è--boundary--.
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----XYZ
Content-Length: 186
------XYZ
Content-Disposition: form-data; name="nome"
Mario
------XYZ
Content-Disposition: form-data; name="file"; filename="a.txt"
Content-Type: text/plain
ciao
------XYZ--Con la boundary ----XYZ le righe di separazione sono ------XYZ (due - più la stringa), e tutte le righe terminano con CRLF: il corpo è di 186 byte. La stringa di boundary non deve comparire nei dati.
Negoziazione del contenuto
Il client dichiara le proprie preferenze con header Accept-*, e il server sceglie la rappresentazione (negoziazione proattiva):
| header | esempio | significato |
|---|---|---|
Accept |
text/html,application/xhtml+xml;q=0.9,*/*;q=0.8 |
tipi accettati, con peso q da 0 a 1 (default 1) |
Accept-Language |
it-IT,it;q=0.9,en;q=0.8 |
lingue preferite |
Accept-Encoding |
gzip, br |
codifiche del contenuto accettate (compressione) |
Accept-Charset |
utf-8 |
codifiche dei caratteri |
La risposta indica la scelta (Content-Type, Content-Language, Content-Encoding) e, con Vary, da quali header dipende. Un client di API usa Accept: application/json.
URI
Un URI (Uniform Resource Identifier, RFC 3986) è una stringa che identifica una risorsa. Un URL è un URI che dice anche come raggiungerla (http://...); un URN la dà per nome (urn:isbn:...). La sintassi generica è:
http://mario:pwd@www.example.com:8080/a/b/../c.html?x=1&y=2#sezione
\__/ \_______/ \_____________/ \__/ \___________/ \_____/ \_____/
scheme userinfo host porta percorso query frammento
\____________________________/
authority| componente | descrizione |
|---|---|
| scheme | protocollo o tipo: http, https, ftp, mailto, ws; non distingue maiuscole |
| authority | [userinfo@]host[:porta]; l'host è un nome di dominio, un IPv4 o un IPv6 fra parentesi quadre (http://[::1]:8080/); porta predefinita: 80 per http, 443 per https |
| percorso | gerarchico con /; distingue maiuscole e minuscole |
| query | dopo ?: coppie chiave=valore separate da & |
| frammento | dopo #: punto interno al documento; non viene mai inviato al server, lo usa il client |
Caratteri riservati e percent-encoding
Nell'URI alcuni caratteri hanno funzione sintattica (riservati: : / ? # [ ] @ ! $ & ' ( ) * + , ; =); gli altri ammessi sono gli unreserved: lettere, cifre e - . _ ~. Tutto il resto, e i riservati usati come dati, si scrive in percent-encoding: % seguito dai due caratteri esadecimali del byte. I caratteri non ASCII si codificano nei byte della loro forma UTF-8.
Esempio. caffè & latte diventa caff%C3%A8%20%26%20latte: è in UTF-8 sono i due byte C3 A8, lo spazio è %20, & è %26. La decodifica è l'inverso; un % non seguito da due cifre esadecimali è un errore (400), e %00 (byte nullo) va rifiutato perché può ingannare i controlli sulle stringhe C. Nei dati dei moduli (x-www-form-urlencoded) anche + vale spazio; nel percorso no.
Un server che serve file decodifica prima di controllare il percorso: /%2e%2e/etc/passwd è /../etc/passwd e va rifiutato (path traversal, Esercizio - Parsing di request line, header e URI (sul modello della prova pratica)).
Risoluzione dei riferimenti relativi
Un documento può contenere URI relativi (../img/a.png) risolti rispetto a una base. L'algoritmo (RFC 3986 par. 5.2) fonde il percorso della base con quello relativo e poi rimuove i segmenti . e ... Con base http://a/b/c/d;p?q:
| riferimento | risultato |
|---|---|
g |
http://a/b/c/g |
./g |
http://a/b/c/g |
/g |
http://a/g |
//g |
http://g |
?y |
http://a/b/c/d;p?y |
#s |
http://a/b/c/d;p?q#s |
../g |
http://a/b/g |
../../g |
http://a/g |
../../../g |
http://a/g (.. non supera la radice) |
Rimozione dei segmenti punto: /a/b/c/./../../g diventa /a/g. Un programma C che implementa scomposizione, percent-encoding e decodifica, rimozione dei segmenti punto e risoluzione dei riferimenti, e verifica tutti gli esempi della RFC, è in Esercizio - URI, scomposizione, percent-encoding e riferimenti relativi (sul modello della prova pratica).
Gli URI nelle richieste
La Request-Line contiene un request-target, che ha quattro forme (RFC 9112 par. 3.2):
| forma | esempio | quando |
|---|---|---|
| origin-form | GET /a/b.html?x=1 HTTP/1.1 |
richiesta a un server (la più comune); l'host sta in Host |
| absolute-form | GET http://www.example.com/a/b.html HTTP/1.1 |
richiesta a un proxy |
| authority-form | CONNECT www.example.com:443 HTTP/1.1 |
solo per CONNECT |
| asterisk-form | OPTIONS * HTTP/1.1 |
OPTIONS sull'intero server |
Il server ricostruisce l'URI completo da schema (dalla connessione), Host e origin-form. Il frammento non compare mai.
Esercizi collegati
- Esercizio - Server con autenticazione Basic, ETag e GET condizionale (sul modello della prova pratica):
401eWWW-Authenticate, Base64,ETag,If-None-Match,304,Cache-Control. - Esercizio - GET condizionale con If-Modified-Since e cache su file (slide HTTP 0.9 e 1.0): lato client della cache.
- Esercizio - Parsing di request line, header e URI (sul modello della prova pratica): percent-decoding, percorso sicuro, URL assoluto.
- Esercizio - URI, scomposizione, percent-encoding e riferimenti relativi (sul modello della prova pratica): RFC 3986, risoluzione dei riferimenti, 41 casi verificati.
- Esercizio - Server HTTP iterativo con GET, HEAD e codici di errore (sul modello della prova pratica): tipo MIME dall'estensione.
Errori tipici
- Credere che
no-cacheimpedisca di memorizzare: serveno-store. - Ignorare il
304e riscaricare il corpo, oppure inviare un corpo in un304. - Confondere
Last-Modified(data) edETag(versione), o dimenticare le virgolette dell'ETag nel confronto. - Scrivere
Authorization: Basic utente:passwordsenza Base64; credere che Base64 protegga la password. - Rispondere
403quando mancano le credenziali (serve401conWWW-Authenticate). - Dimenticare
Content-Typeo dichiarare quello sbagliato; servire tutto cometext/html. - Decodificare il percent-encoding dopo i controlli sul percorso; decodificare due volte; trattare
+come spazio nel percorso. - Aspettarsi il frammento (
#...) nella richiesta: non viene inviato. - Confrontare il percorso senza distinguere maiuscole e minuscole, o lo schema e l'host distinguendole.
Domande d'esame
1. Un client ha in cache una risorsa con ETag: "v7" e Cache-Control: max-age=60. Descrivere cosa succede alla richiesta dopo 30 s e dopo 90 s.
Traccia. A 30 s la copia è fresca (30 < 60): la cache la serve senza contattare il server. A 90 s è scaduta: il client invia una richiesta condizionale con If-None-Match: "v7". Se la risorsa non è cambiata il server risponde 304 Not Modified senza corpo e la copia torna fresca per altri 60 s; se è cambiata risponde 200 con il corpo nuovo e un nuovo ETag.
2. Descrivere l'autenticazione Basic: messaggi scambiati e perché si usa solo con HTTPS.
Traccia. Il client chiede la risorsa; il server risponde 401 con WWW-Authenticate: Basic realm="..."; il client ripete con Authorization: Basic base64(utente:password) (esempio mario:segreto -> bWFyaW86c2VncmV0bw==). Base64 non cifra: chiunque intercetti la richiesta ottiene la password, e il browser la rimanda a ogni richiesta; quindi serve TLS.
3. Codificare caffè & latte in percent-encoding e dire cosa fa un server con GET /%2e%2e/etc/passwd.
Traccia. caff%C3%A8%20%26%20latte (è = C3 A8 in UTF-8). Il server decodifica %2e%2e in .. prima di controllare il percorso, ottiene /../etc/passwd e lo rifiuta (403 o 404): se controllasse prima della decodifica, l'attaccante uscirebbe dalla radice dei documenti.
Versione ripasso
- Cache. Privata (browser) o condivisa (proxy, CDN). Chiave: metodo + URI (+ header di
Vary). Mai perPOSTo conno-store. Fresca se età < durata:max-age=N(os-maxageper le condivise), poiExpires, poi euristica ~10% del tempo daLast-Modified. Età =Date/Age. Esempio:Date 10:00,max-age=3600: alle 10:30 fresca (nessun pacchetto), alle 11:05 scaduta (rivalida) (HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encodingHTTP/1.1 (oggi RFC 9110 e 9112) rende la connessione persistente di default (si chiude solo con "Connection: close"), rende obbligatorio l'header Host (virtual hosting) e introduce i nuovi metodi PUT, DELETE, OPTIONS, TRACE, Expect: 100-continue, richieste di intervalli (206) e Transfer-Encoding: chunked; con la connessione persistente il client deve sapere dove finisce ogni risposta: lunghezza del corpo nell'ordine HEAD/1xx/204/304 senza corpo, Transfer-Encoding chunked, Content-Length, altrimenti fino alla chiusura; il chunked divide il corpo in blocchi preceduti dalla lunghezza in esadecimale, termina con un chunk 0 e un trailer facoltativo, e si decodifica contando i byte dichiarati (non cercando CRLF).HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encoding →). - Rivalidazione.
Last-Modified->If-Modified-Since;ETag: "abc"(versione, tra virgolette,W/= debole) ->If-None-Match: "abc". Uguale:304 Not Modifiedsenza corpo e nuova freschezza; diverso:200+ corpo + nuovo validatore.If-MatchinPUT/DELETEevita i lost update (412).
| direttiva | effetto |
|---|---|
max-age=N |
fresca N secondi |
public / private |
anche condivise / solo cache dell'utente |
no-cache |
memorizza ma rivalida sempre |
no-store |
non memorizzare |
must-revalidate |
scaduta: niente uso senza rivalida |
Vary: Accept-Encoding: copie diverse per valori diversi.
- Autenticazione. Sfida/risposta:
401+WWW-Authenticate: <schema> realm="..."; poiAuthorization: ....403= niente diritti. Proxy:407,Proxy-Authenticate,Proxy-Authorization. - Basic.
Authorization: Basic base64(utente:password);mario:segreto=bWFyaW86c2VncmV0bw==;Aladdin:open sesame=QWxhZGRpbjpvcGVuIHNlc2FtZQ==. Base64 non cifra: solo con TLS; la password è rimandata a ogni richiesta. - Digest.
HA1 = H(utente:realm:password),HA2 = H(metodo:uri),response = H(HA1:nonce:nc:cnonce:qop:HA2); esempio RFC 2617 (Mufasa) =6629fae49393a05397450978507c4ef1. Bearer (OAuth) e cookie come alternative (Crittografia asimmetrica, RSA e TLSCrittografia asimmetrica (a chiave pubblica): chiave di cifratura pubblica v_B, chiave di decifratura privata s_B, matematicamente legate; C = E_vB(P), P = D_sB(C); dà riservatezza. I certificati digitali, emessi da una Certificate Authority e firmati con la sua chiave privata, legano un'identità a una chiave pubblica. Firma digitale: hash del messaggio cifrato con la chiave privata; garantisce autenticità, integrità e non ripudio. RSA: si scelgono due primi grandi p e q, N = pq, phi(N) = (p-1)(q-1), e coprimo con phi(N), d = e^(-1) mod phi(N); chiave pubblica (N, e), segreta (N, d); cifratura c = m^e mod N, decifratura m = c^d mod N con m < N (teorema di Eulero); sicura finché la fattorizzazione è difficile (N di almeno 2048 bit); il padding casuale (PKCS#1 v1.5: 00 02 [casuale] 00 [m]) difende da malleabilità e determinismo. La firma RSA è s = m^d mod N, verificata con s^e mod N. TLS (su TCP) autentica gli estremi con il certificato, cifra i dati con una chiave di sessione simmetrica e garantisce l'integrità con i MAC; da TLS 1.0 a 1.3 la chiave si ricava con Diffie-Hellman e l'handshake si accorcia. DTLS è la versione per UDP.Crittografia asimmetrica, RSA e TLS →). - MIME.
Content-Type: tipo/sottotipo[; charset=...];text/html; charset=utf-8,application/json,application/pdf,image/png,application/x-www-form-urlencoded(nome=Mario&eta=30),multipart/form-data; boundary=...(parti--boundary, chiusura--boundary--),application/octet-stream= sconosciuto. Tipo dall'estensione con una tabella;nosniffcontro lo sniffing. - Negoziazione.
Accept(q0-1),Accept-Language,Accept-Encoding(gzip, br),Accept-Charset; risposta conContent-Type/Content-Language/Content-EncodingeVary. - URI (RFC 3986).
scheme://userinfo@host:porta/percorso?query#frammento; IPv6 tra[ ]; porta predefinita 80 / 443; schema e host case-insensitive, percorso case-sensitive; il frammento non va al server. - Percent-encoding. Unreserved: lettere, cifre,
- . _ ~. Altrimenti%HHdel byte (UTF-8):caffè & latte=caff%C3%A8%20%26%20latte.+= spazio solo nei moduli.%rotto o%00: rifiutare. Decodificare prima di controllare il percorso:/%2e%2e/etc/passwd=/../etc/passwd(path traversal). - Riferimenti relativi (base
http://a/b/c/d;p?q):g->/b/c/g,/g->http://a/g,//g->http://g,?y->.../d;p?y,#s->...?q#s,../g->/b/g,../../../g->/g./a/b/c/./../../g->/a/g. - Request-target. origin-form (
/a?x=1+Host), absolute-form (a un proxy), authority-form (CONNECT host:443), asterisk-form (OPTIONS *). - Messaggi da saper scrivere.
GET /logo.png HTTP/1.1 HTTP/1.1 304 Not Modified
Host: www.example.com ETag: "abc123"
If-None-Match: "abc123" Cache-Control: max-age=3600
HTTP/1.1 401 Unauthorized GET /private/riservato.txt HTTP/1.1
WWW-Authenticate: Basic realm="Area" Authorization: Basic bWFyaW86c2VncmV0bw==
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----XYZ
Content-Length: 186 (corpo: ------XYZ ... ------XYZ--)Cronologia della cache.
t = 0:200,ETag "abc123",max-age=3600(si memorizza);t = 1800 s: servita dalla cache, nessun pacchetto;t = 3700 s:If-None-Match->304, freschezza rinnovata; file cambiato:200conETag "def456".Errori tipici:
no-cachecreduto un divieto (èno-store);304con corpo o ignorato; Basic senza Base64 o creduto sicuro;403al posto di401;Content-Typemancante; controllo del percorso prima della decodifica;+come spazio nel percorso; frammento atteso nella richiesta.
Esercizi su questo argomento
- Esercizio - GET condizionale con If-Modified-Since e cache su file (slide HTTP 0.9 e 1.0)
- Esercizio - Parsing di request line, header e URI (sul modello della prova pratica)
- Esercizio - Proxy HTTP con filtro degli host (sul modello della prova pratica)
- Esercizio - Server con autenticazione Basic, ETag e GET condizionale (sul modello della prova pratica)
- Esercizio - Server HTTP con CGI (sul modello della prova pratica)
- Esercizio - Server HTTP iterativo con GET, HEAD e codici di errore (sul modello della prova pratica)
- Esercizio - Servizio REST con JSON (sul modello della prova pratica)
- Esercizio - URI, scomposizione, percent-encoding e riferimenti relativi (sul modello della prova pratica)
Teoria collegata
- CGI e applicazioni web dinamiche
- DNS, proxy web, HTTP CONNECT e gateway applicativi
- HTTP 0.9 e 1.0 - struttura dei messaggi, header e parsing
- HTTP 1.1 - connessioni persistenti, Content-Length e chunked transfer encoding
- Protocolli per i servizi multimediali
- Streaming adattativo e DASH
- Web service, XML, JSON, SOAP e REST
- WebSocket, QUIC e HTTP-3