No results found
Dopo tanti anni di stasi, negli ultimi tempi c'è stata questa repentina evoluzione dei numeri di versione del protocollo http, che per molto tempo è stato lasciato quello che era e che oggi viene riscoperto per varie ragioni che illustreremo in questo tutorial. Oltre che dell’evoluzione dell’http, in questo tutorial parleremo di Quic, che un po' l’evoluzione della versione http 2 originariamente sviluppata da Google, adesso distinta come G Quic.
Da qualche anno si vede si sente parlare di http 2 però la sua implementazione non è una cosa immediata e non è stato molto utilizzato, malgrado la velocità superiore che consente. Il protocollo Speedy e poi l’http2 sono tornati alla ribalta a seguito dell'attacco informatico Crime, ossia il leakage che coinvolgeva il TLS e la compressione degli header; in quell’occasione tutti si affrettarono a disattivarlo, anche quelli che lo avevano attivato per prova
La storia dell’http risale a una trentina di anni fa, perché è del 1991 la prima versione documentata del protocollo, che era la 0.9. Poi per 30 anni ci siamo fatti bastare http 1 e adesso di botto siamo alla 3.
Dalla nascita, di fatto c'è stato un lavoro di ratifica degli IETF della versione 1.0 aggiungendo degli Header, alcuni meccanismi per la favorire il proxying il caching, ma di fatto tutti utilizzano da tantissimo tempo la versione 1.1, tanto che tutt'ora buona parte del web si regge ancora su quella che risale, almeno come, specifica al lontano 1999.
Quindi ci si può chiedere perché a un certo punto, nel 2015, Google si sia messa a lavorare con Speedy, che poi è diventato http2. Ebbene, perché da più parti si è cercato di superare i limiti dell’http 1 e perché si cerca di trovare una risposta alle crescenti esigenze, visto che comunque adesso praticamente tutto viaggia attraverso l’http.
L’immagine seguente descrive l’evoluzione del protocollo http (fonte: blog.cloudflare.com).
In realtà l’evoluzione dell’http non è ferma al 1999, perché da allora c'è stata una continua e crescente adozione di protocolli che aggiungevano sicurezza ad http, quindi già dal 1995 si è iniziato con SSL, poi di fatto c’è stata l’evoluzione in RFC2246 e poi TLS, fino alla versione 1.3 (immagine seguente; fonte blog.cloudflare.com).
Adesso la consideriamo una cosa separata perché effettivamente questi sono ulteriori protocolli che si vanno ad aggiungere ad http, mentre il problema è che Google voleva provare a risolvere questa stratificazione, la quale se da una parte è più efficiente perché rende possibile continuare a usare http 1.1 così com'è (perché se lo si “imbusta” dentro TLS diventa https e si utilizza senza modificarlo) dall'altra crea problemi di latenza e in generale di performance della connessione. Perciò serve ridisegnare un unico protocollo, invece che utilizzarne uno esistente e “corredarlo” di ulteriori protocolli che lo rendono sicuro. Serve, insomma, un protocollo che implementi nativamente il livello di sicurezza offerto dalla combinazione di http 1.1, SSL e TLS.
Per comprendere il concetto se vediamo cosa succede tipicamente quando si stabilisce una connessione https; ci aiutiamo con l’immagine seguente, nella quale si vede una serie di scambi tra server e client: a sinistra c’è un client (un browser) e a destra un server.
I protocolli coinvolti sono tre perché occorre instaurare una connessione a livello TCP, sopra la connessione TCP/IP inizializzare una sessione TLS e poi finalmente quando questo canale si è aperto, si può fare la richiesta http vera e propria. Quindi c'è uno scambio continuo di dati perché soltanto per aprire la connessione TCP è necessario fare un handshake e quindi inviare la solita sequenza di pacchetti TCP SYN, TCP SYN + ACK , poi bisogna avviare la connessione TCP e quando il canale è stabilito bisogna fare l’handshake TLS quindi Client Hello, Server Hello e TLS Finish, poi finalmente si può fare la richiesta e ottenere (se possibile) dal server la risposta.
Tutto questo lavoro, il client lo deve fare ogni volta che deve fare una nuova richiesta e questo chiaramente crea problemi di performance e di latenza; il problema è che si perde un po' di efficienza perché bisogna rifare tante volte questa operazione.
Per migliorare le prestazioni, rimanendo in ambito http 1, una delle prime cose che si è pensato di fare è stato riutilizzare la connessione stabilita e quindi il lavoro fatto per stabilirla, ovvero una volta che è stata aperta la connessione TCP ed è stata già negoziata una sessione TLS, magari la si tiene aperta e se occorre chiedere più cose al server le si chiede nella stessa connessione.
Nell’immagine seguente vediamo quindi due richieste differenti: c'è la richiesta 1 con la sua risposta e la richiesta 2 con la relativa risposta.
Questo meccanismo nasceva in un’epoca in cui i siti web comunque erano ancora statici e le pagine web avevano bisogno di fare poco più di una sola richiesta, cioè oltre all’HTML, magari caricare qualche immagine GIF attorno.
Ecco, con http 1, anziché fare una richiesta per ogni singola immagine e aprire ogni volta una nuova connessione, le richieste si potevano impilare; quindi una cosa che si può fare è il pipelining, ossia piuttosto che fare una richiesta, attendere una risposta dl server e poi farne un’altra e attendere la risposta corrispondente, quindi elaborare una procedura completa per ogni singola richiesta, è possibile inviare dal cliente le richieste tutte insieme in sequenza 1 2 3 e poi il server risponderà.
Questo di fatto è l’utilizzo dell’http che facciamo quotidianamente e che la maggior parte delle applicazioni, non soltanto i browser, utilizza. Oggigiorno si tende a modulare la profondità del pipelining, ossia una connessione stabilita viene mantenuta aperta con un keep-alive per un certo numero di secondi e in questo intervallo si elabora una serie di richieste.
Questa però non è una soluzione efficiente, almeno non secondo Google e gli IETF , perché resta il problema dell’head of line blocking: ciò significa di fatto che sebbene si possano inviare tante richieste una dopo l'altra, anche se le si può fare insieme sulla stessa connessione, il server deve rispondere in ordine, quindi fintanto che non è stata ricevuta la risposta alla prima richiesta non è possibile ricevere dati sulla seconda e via di seguito. Questo può essere un problema perché negli anni i siti web sono diventati sempre più complessi e non trasmettono soltanto immagini: per esempio se andiamo su YouTube dobbiamo aprire uno stream video, il quale non è detto che sia contemplato in un'unica richiesta http, perché spesso si tratta di tante richieste consecutive con le quali il browser va richiedendo tanti tanti frammenti e se se ne perde uno per strada anche se il server che aveva già pronto il lavoro per spedire tutto il resto in realtà deve ricominciare da capo.
Alla fine non è detto che il semplice pipelining sia una possibile soluzione, infatti la soluzione adottata dalla maggior parte dei browser è quella di aprire una batteria di connessioni; questo può essere verificato aprendo gli strumenti di sviluppo di un qualsiasi browser e andando nella tab di network: qui si vede che quando si fa una richiesta ad un sito non appare una sola connessione TCP aperta ma se ne vedono tante, perché il client prova a inviare più richieste in parallelo (immagine seguente).
Questo va bene, però rimane il problema di prima che per ogni connessione TCP e ogni handshake TLS si perde del tempo prezioso, quindi più sono le richieste di connessione aperte, più tempo occorre; insomma, si ripresenta il problema della latenza. Http2, che è la versione standardizzata di quel protocollo nato in casa Google con il nome di Speedy, prova ad affrontare anche questo problema; in realtà ne affronta tanti altri, perché per esempio definisce uno schema di compressione anche degli header http. Questo perché quando http è nato, è stato progettato solo per trasferire ipertesti, quindi pensare che anche le parti di protocollo come le intestazioni (gli header http) fossero testo non rappresentava un grosso problema dal punto di vista delle performance, perché
tanto poi in risposta doveva comunque arrivare un HTML e che sopra ci fosse scritta la data dell'ultima modifica o la versione del protocollo non dava fastidio ad alcuno.
Invece adesso che attraverso http ci si fa passare di tutto, pensare che le intestazioni siano scritte in Husky e quindi occupino molto più spazio di quello che potrebbe essere una rappresentazione binaria, può essere un problema per la latenza; considerare che diverse centinaia di byte per connessione siano occupati dagli header non è accettabile, perché si occupa banda per qualcosa che non sono i dati richiesti, ovvero il payload.
Allora http 2 introduceva uno schema per comprimere anche gli header, oltre che per evitare parzialmente il problema della head of line blocking, quindi definiva uno schema che poteva consentire al server di rispondere con un pezzetto di un'altra risposta anche se ancora non aveva finito di inviare tutti i dati della precedente.
Questo ha rappresentato un passo avanti ma non particolarmente rilevante, perché comunque in particolari applicazioni occorre scegliere tra sicurezza e velocità: per accelerare le procedure occorre semplificarle, a discapito dei controlli eseguibili e comunque più un protocollo è complesso, meno è sicuro.
In un protocollo che è diventato l'ossatura di Internet, mettere mano non è facile e infatti http2 è stato migliorato ma le migliorie non hanno risolto completamente il problema del head of line blocking che, era l'obiettivo della revisione del protocollo; questo perché sotto c’è comunque il TCP, che deve gestire a livello di trasporto gli eventuali errori di trasmissione, le ritrasmissioni è l'ordinamento dei pacchetti, quindi prima che i dati arrivino al browser e che esso li possa interpretare sotto forma di pacchetti TLS prima e di pezzi di http dopo, c'è il TCP che fa il “lavoro sporco” cioè prova a riordinare e ritrasmettere le cose. Quindi se ci sono degli errori di trasmissione, se il canale di comunicazione non è stabile (tipico è il caso di una connessione dati su rete cellulare, quando si passa dalla rete WiFi alla connessione 3G/4G perché si esce di casa) quello che succede con il TCP è che bisogna ricominciare da capo perché la connessione cade e bisogna ritrasmettere tutto. Ecco perché il problema dell’head of line blocking di fatto non si risolve neppure adottando l’http2.
Ma a parte questo, il problema grosso è di sicurezza, giacché quando è uscito Crime ci si è resi conto che malgrado i vantaggi che ha portato, comprimere gli header in realtà ha generato una vulnerabilità, dovuta al fatto che la maggior parte del testo negli header http è sempre lo stesso, perché il nome dei campi degli header http è sempre quello.
In generale, quando utilizziamo sistemi di cifratura e di compressione, il fatto di utilizzare del testo noto non è mai una bella cosa, perché un attaccante potrebbe fare delle analisi di criptoanalisi: sapendo che è all'inizio la connessione http inizierà sempre con le stringa http compressa, l'attaccante di fatto ha già in mano un'informazione per cercare di fare criptoanalisi e può quindi decrittografare anche un contenuto cifrato.
Siccome in http la comunicazione iniziamo sempre con delle stringhe, è facile fare criptoanalisi. Con l’arrivo di Crime la gente che aveva iniziato a utilizzare Speedy corse subito ai ripari disattivando subito compressione degli header; chi aveva attivato la compressione deflate su TLS l’ha disattivata immediatamente.
Quindi alla fine http 2 è stato un po’ tralasciato per via dei compromessi che il suo utilizzo impone. È facile trovarlo per esempio su un sito che usa cloudflare come CDN.
Quindi nel tentare una correzione, se non va Quic per qualche motivo, sicuramente andrà http 2 e se poi non va neanche http 2 allora si ritorna alla http 1.
In mezzo alla confusione creata attorno all’http, Google si mette all’opera e cerca di sviluppare un proprio protocollo di trasporto; per risolvere il problema del doppio handshake (prima quello TCP e poi quello di TLS) crea un protocollo di trasporto che ha un handshake solo e che include già TLS, quindi Google Quic e la versione Quic ratificata fanno proprio questo: per il setup del canale di comunicazione basta un solo giro invio e ricezione perché nell’handshake si fanno entrambe le cose (immagine seguente).
Ma la cosa più importante è che siccome non si può appoggiare al TCP, il tutto si poggia sulle APP di trasporto UDP; questo, in reti che non sono ben configurate è facile che causi problemi.
Infatti quello che offre il TCP è tutta una serie di meccanismi per evitare le congestioni, quindi capire quando un pacchetto s'è perso per strada e provare a ritrasmetterlo è un algoritmo molto complesso in TCP.
Invece l’UDP lascia questa responsabilità a livello applicativo, nel senso che è l'applicazione che fa una richiesta e se non ottiene una risposta entro un tempo ritenuto ragionevole a seconda dell’applicazione, possono verificarsi due eventualità: la prima è che l'applicazione ritiene il fatto accettabile e se durante uno streaming salta un pezzetto di voce non sta a richiedere al server qual era quel pezzetto di voce, ma va avanti; chiaramente per una conversazione in real time questo non è possibile.
La seconda opzione è che sono delle applicazioni che richiedono che i dati vengano sempre trasferiti: se dobbiamo far viaggiare una pagina web non possiamo accollarci il problema di avere saltato un pezzetto, come ad esempio un’immagine o una parte di testo. In quel caso dobbiamo farcelo ritrasmettere a tutti i costi.
Quindi tutto quello che prima faceva il TCP, ossia gestire le ritrasmissioni, gli errori e lo faceva in un modo che non saturasse la rete, se non si può usare il TCP deve farlo qualcos’altro. L’idea di Google è stata quindi utilizzare UDP e implementare tutto il resto direttamente nell'applicazione, quindi non si va a toccare lo stack di rete del kernel, ma si fa direttamente tutto nello spazio applicativo.
Quic viene definito protocollo di trasporto, perché è a servizio dell’http, ma in realtà è un protocollo che viene direttamente implementato nelle applicazioni: non gira nel nello stack di rete del sistema operativo ma gira nel browser. Avendo la possibilità di lavorare su UDP non ha tutti i problemi di cui soffre il TCP, nel senso che consente di trasmettere frammenti di risposte http fuori ordine e poi è l'applicazione che le ordina tutte insieme.
È questo il motivo per cui cloudflare spinge molto su questo, perché fa CDN e quindi prevalentemente una rete di proxy; nel caso in cui un utente si colleghi alla loro CDN e debba richiedere delle risorse, che in realtà sono “proxate” su server differenti e magari uno è più lento dell'altro, anziché attendere quello più lento, intanto la CDN spedisce le cose che può spedire.
Questo è effettivamente implementato con Quic.
Quic viene concepito come evoluzione di http 2, ma in realtà http 2 semplicemente è servito per capire un po' cosa sarebbe successo a mettere mano all’http. È stato necessario incrementare il numero di versione ulteriormente perché sebbene sia molto simile ad http 2, c'era proprio una cosa che non era compatibile con Quic ed era lo schema di compressione degli header (H Pack) perché è incompatibile con la gestione interlacciata multiplexata dei pacchetti di Quic.
Http 3 definisce lo standard di funzionamento di http 2 su Quic invece che su TCP + TLS.
Quic (anche noto come http 3) è molto simile all’http 2 ma ci sono queste differenze profonde, perché al di là del fatto che si lavori sui protocolli, definire un protocollo di rete sicuro performante è un lavoro veramente difficile; i membri delle commissioni degli IETF si riuniscono per per mesi e mesi per stabilire meccanismi affidabili.
Però c'è anche un'altra implicazione dell’http 3: aver portato molti dei servizi che prima erano implementati livello di sistema operativo direttamente nel codice delle applicazioni; infatti a lavorare con Quic più http 3, di fatto è il browser che fa tutto il lavoro. Dal punto di vista del sistema operativo c'è solo un socket UDP aperto e questo significa che l'applicazione si rende indipendente dal sistema operativo e indipendente nel suo ciclo di sviluppo; quindi se ci si accorge che c'è un problema nello stack di trasporto, non bisogna attendere che sia installata la relativa patch nel sistema operativo, ma con l'aggiornamento del browser va tutto a posto.
Ci sono pro e contro in questa filosofia; una cosa certa è che dal punto di vista degli amministratori di rete e dei sistemisti, in questo momento Quic e http 3 sono un po' una scatola chiusa, nel senso che i firewall che fanno inspection vedono solo una connessione UDP e non hanno possibilità di capire cosa c'è dentro; inoltre i proxy non si possono più utilizzare perché non supportano il protocollo, quindi anche per questo l'adozione non sarà così repentina come magari ci si poteva immaginare.
Per capire quale protocollo si sta utilizzando durante una connessione Internet, ovvero se si sta stabilendo una connessione http 3, la cosa più semplice da fare è andare su qualche sito che lo supporta, come per esempio cloudflare, quindi aprire gli “strumenti da sviluppatore” nel browser e aprire la tab network (rete) quindi andare a vedere se c'è una colonna che si può attivare, che riporta qual è il protocollo che supporta.
L’immagine seguente riporta lo screenshot in un contesto in cui il traffico UDP verso l'esterno sulla porta 443 è chiuso, quindi il browser automaticamente comunica con l’http 2 perché trova disponibile solo quello. Se invece trovasse disponibile la UDP 443 e il server la supporta, il browser utilizzerebbe http3 e quindi Quic; questo se i browser sono aggiornati.
Quindi se dovessimo navigare su un server che ha una versione più vecchia delle librerie, magari potremmo trovare scritto GQuic al posto di http 3, oppure http2/Speedy. Insomma, i browser sanno riconoscere le differenze tra i vari standard.
A livello di rete, analizzando e visualizzando quello che passa catturando del traffico con wireshark; se si utilizza http2 si vede che si continua ad utilizzare TLS, quindi c’è aperta una normalissima sessione TLS sopra TCP.
In questo caso non è possibile, meno di non creare un attacco di tipo “Man in the middle”, la Deep inspection, però si ottiene un'idea chiara di chi sta comunicando con chi a livello di server e di client e sul fatto che si stanno parlando in TLS. L’immagine seguente propone come si presenta il traffico analizzato attraverso Wireshark. In un caso del genere (riga evidenziata).
Facendo la stessa analisi su una comunicazione con Quic, vediamo che c’è una serie di frame UDP all'interno dei quali ci sono degli header che sostanzialmente implementano quelle due funzionalità che esistevano in TCP e non esistono in UDP, perché UDP è connectionless, mentre qui c’è bisogno di gestire una connessione; Quic lo fa con un connection ID (CID), quindi assegna un identificativo alla connessione ed utilizza quello, ma chiaramente ha bisogno anche di riordinare i pacchetti, visto che UDP non consegna i pacchetti in ordine (non garantisce l'ordinamento come il TCP) e quindi, allo scopo, c'è il packet number.
Una cosa interessante da notare e che con l’adozione di Quic migliora l'utilizzo delle risorse, perché quando si fa multiplexing con il TCP in un sistema, sulla stessa interfaccia con lo stesso IP non è possibile disporre di più di 65.535 porte: sebbene questo sembri un numero enorme, se ad un server molto trafficato tanti browser fanno varie richieste ciascuno contemporaneamente, le connessioni diventano tante da saturare lo stack di rete di una macchina e a quel punto bisognerebbe aumentare le risorse a disposizione, altrimenti ci saranno dei client che non troveranno porte libere e quindi una connessione TCP con essi non potrà essere effettuata.
Guardando la colonna di destra dell’immagine precedente, dove sono riportati i CID, notiamo che il connection ID di Quic è decisamente più lungo di 2 byte; ciò significa che a parità di risorse (e questo è uno dei motivi per grossi provider di servizi per le aziende come Google spingono) è possibile imbustare molte più connessioni e molti più flussi all'interno delle stesse porte. Quindi gestendo una sola porta UDP verso un client, quest’ultimo in realtà imbusta dentro Quic tante connessioni e tante sessioni e quindi diviene possibile trasferire tutto il contenuto di una pagina (per esempio tutte le immagini che gestisce e quant'altro) facendo un uso più efficiente delle risorse di rete.
Giunti a questo punto viene da domandarsi se http3 sia già in uso. La risposta è che sono pochissimi i servizi che lo supportano, proprio perché da una parte ognuno si è fatto le sue implementazioni dei server e dall’altra non è facile mantenere una struttura i cui server siano configurati correttamente per http3.
Però ci sono grossi provider che lo gestiscono, quindi se ad esempio un server si mette dietro una CDN che lo supporta, magari il server non supporta http 3 ma in realtà la CDN servirà i client in http3.
Per quanto riguarda i client, praticamente tutti lo supportano sia in mobile che in che desktop, nelle nelle tre piattaforme principali: Windows, MacOS e Linux. C’è molto interesse, soprattutto perché a parità di risorse in campo, il protocollo aumenta la velocità di soddisfazione delle richieste dei browser.
Sicuramente dovranno prima adeguarsi i vari vendor di firewall, antivirus eccetera, quindi soggetti come Apache, Tomcat ecc. che attualmente rimangono sulla gestione di connessioni TCP su TLS per l’implementazione dei web server.
Oggigiorno ci sono delle librerie che implementano il protocollo http 3 a tutto tondo, però integrare una libreria del genere in un server concepito 20 anni fa e che ha tutta un'altra architettura ha delle implicazioni profonde (per esempio appena si gestisce l’utente Virtual host sballa tutto).
Comunque il problema del passaggio all’http 3 è più sentito non tanto dai vendor di web server quanto dai produttori di tecnologie di sicurezza, perché per essi è concreto. Cioè se in questo momento ci si trova in una rete in cui il traffico verso UDP 443 è aperto verso l'esterno, i client potrebbero comunicare in Quic. Ma questo è un problema, perché magari si opera in una configurazione in cui non c'è una regola particolare, però all'improvviso i client cominciano a evitare, almeno per una certa classe di servizi (quelli di Google oppure le SDN di cloudflare), tutti gli altri blocchi messi (filtraggi di contenuto e quant'altro) semplicemente perché spontaneamente hanno iniziato a utilizzare http 3.
Quindi anche se non è così largamente diffuso, http 3 è già supportato dai client, pertanto occorre prestare attenzione anche a come sono gestite le reti, perché di fatto la superficie di attacco è aumentata proprio per la possibilità di passare a un protocollo ancora non gestito dalle soluzioni di sicurezza. Ad esempio, navigando su Google pur senza applicare alcuna regola, si va in http3 a meno di non chiudere sul firewall la porta UDP 443, allorché il browser ritorna con http 2. Su Google può accadere che navigando con Chrome, se magari si chiude la porta per ipv4 il browser conosce gli indirizzi ipv6 di frontiera di Google e utilizza quelli, aggirando il blocco.
I cyber-criminali stanno diventando sempre più creativi nell’implementare sistemi di comunicazione verso i server di Command & Control e l’utilizzo di Quic e http3 potrebbe essere sfruttato allo scopo. Ci sono stati anche dei malware che hanno utilizzato il DNS come protocollo di Command & Control e in quel caso gli attaccanti si sono registrati un dominio e tanti sub-domini e il virus, in base alla richiesta DNS, richiedeva un certo sub-dominio piuttosto che a un altro è così comunicava quello che voleva. In ogni caso se il server viene compromesso, i client non sono protetti, quindi la sicurezza non è garantita, perché si può curare la sicurezza per le connessioni in entrata al server ma non su quelle in uscita verso i client (browser).
Essere in grado di controllare i protocolli di connessione e renderli sicuri, impedendo che diventino veicolo per accedere da remoto ai server e portare attacchi magari silenti, ovvero agire da Command & Control, è sempre più fondamentale, perché certi attacchi fanno entrare un malware nel sistema e questo apre una porta all’hacker dalla quale questo può fare ciò che vuole.