Passa al contenuto principale

7. Considerazioni sulla sicurezza (Security Considerations)

Questa sezione descrive potenziali aree di preoccupazione per la sicurezza con QPACK:

  • Uso della compressione come un oracolo basato sulla lunghezza per verificare ipotesi su segreti che vengono compressi in un contesto di compressione condiviso.

  • Denial of service risultante dall'esaurimento della capacità di elaborazione o di memoria presso un decoder.

7.1 Sondaggio dello stato della tabella dinamica (Probing Dynamic Table State)

QPACK riduce la dimensione codificata delle sezioni di campo sfruttando la ridondanza inerente ai protocolli come HTTP. L'obiettivo finale di questo è ridurre la quantità di dati richiesta per inviare richieste o risposte HTTP.

Il contesto di compressione utilizzato per codificare i campi di header e trailer può essere sondato da un attaccante che può sia definire i campi da codificare e trasmettere sia osservare la lunghezza di quei campi una volta codificati. Quando un attaccante può fare entrambe le cose, può modificare adattivamente le richieste per confermare ipotesi sullo stato della tabella dinamica. Se un'ipotesi viene compressa in una lunghezza più breve, l'attaccante può osservare la lunghezza codificata e dedurre che l'ipotesi era corretta.

Questo è possibile anche sul protocollo Transport Layer Security ([TLS]) e sul protocollo di trasporto QUIC ([QUIC-TRANSPORT]), perché mentre TLS e QUIC forniscono protezione della riservatezza per il contenuto, forniscono solo una quantità limitata di protezione per la lunghezza di quel contenuto.

Nota: Gli schemi di padding forniscono solo protezione limitata contro un attaccante con queste capacità, potenzialmente forzando solo un numero aumentato di ipotesi per apprendere la lunghezza associata a una data ipotesi. Gli schemi di padding funzionano anche direttamente contro la compressione aumentando il numero di bit trasmessi.

Attacchi come CRIME ([CRIME]) hanno dimostrato l'esistenza di queste capacità generali dell'attaccante. L'attacco specifico ha sfruttato il fatto che DEFLATE ([RFC1951]) rimuove la ridondanza basata sulla corrispondenza dei prefissi. Ciò ha permesso all'attaccante di confermare le ipotesi un carattere alla volta, riducendo un attacco in tempo esponenziale in un attacco in tempo lineare.

7.1.1 Applicabilità a QPACK e HTTP (Applicability to QPACK and HTTP)

QPACK mitiga, ma non previene completamente, gli attacchi modellati su CRIME ([CRIME]) forzando un'ipotesi a corrispondere a un'intera riga di campo piuttosto che a singoli caratteri. Un attaccante può solo apprendere se un'ipotesi è corretta o meno, quindi l'attaccante è ridotto a un'ipotesi a forza bruta per i valori di campo associati a un dato nome di campo.

Pertanto, la fattibilità del recupero di valori di campo specifici dipende dall'entropia dei valori. Di conseguenza, i valori con alta entropia sono improbabili da recuperare con successo. Tuttavia, i valori con bassa entropia rimangono vulnerabili.

Gli attacchi di questa natura sono possibili ogni volta che due entità reciprocamente diffidenti controllano richieste o risposte che vengono poste su una singola connessione HTTP/3. Se il compressore QPACK condiviso permette a un'entità di aggiungere voci alla tabella dinamica e all'altra di fare riferimento a tali voci durante la codifica di righe di campo scelte, allora l'attaccante (la seconda entità) può apprendere lo stato della tabella osservando la lunghezza dell'output codificato.

Ad esempio, richieste o risposte da entità reciprocamente diffidenti possono verificarsi quando un intermediario:

  • invia richieste da più client su una singola connessione verso un server di origine, o

  • prende risposte da più server di origine e le colloca su una connessione condivisa verso un client.

I browser web devono anche assumere che le richieste effettuate sulla stessa connessione da diverse origini web ([RFC6454]) siano effettuate da entità reciprocamente diffidenti. Altri scenari che coinvolgono entità reciprocamente diffidenti sono anche possibili.

7.1.2 Mitigazione (Mitigation)

Gli utenti di HTTP che richiedono riservatezza per i campi di header o trailer possono utilizzare valori con entropia sufficiente a rendere impraticabili le ipotesi. Tuttavia, questo è impraticabile come soluzione generale perché costringe tutti gli utenti di HTTP a prendere misure per mitigare gli attacchi. Imporrebbe nuovi vincoli su come viene utilizzato HTTP.

Piuttosto che imporre vincoli agli utenti di HTTP, un'implementazione di QPACK può invece vincolare come viene applicata la compressione al fine di limitare il potenziale per il sondaggio della tabella dinamica.

Una soluzione ideale segrega l'accesso alla tabella dinamica in base all'entità che sta costruendo il messaggio. I valori di campo che vengono aggiunti alla tabella sono attribuiti a un'entità, e solo l'entità che ha creato un particolare valore può estrarre quel valore.

Per migliorare le prestazioni di compressione di questa opzione, alcune voci potrebbero essere contrassegnate come pubbliche. Ad esempio, un browser web potrebbe rendere disponibili i valori del campo di header Accept-Encoding in tutte le richieste.

Un encoder senza buona conoscenza della provenienza dei valori di campo potrebbe invece introdurre una penalità per molte righe di campo con lo stesso nome di campo e valori diversi. Questa penalità potrebbe causare un gran numero di tentativi di indovinare un valore di campo a far sì che il campo non venga confrontato con le voci della tabella dinamica nei messaggi futuri, impedendo efficacemente ulteriori ipotesi.

Questa risposta potrebbe essere resa inversamente proporzionale alla lunghezza del valore del campo. La disabilitazione dell'accesso alla tabella dinamica per un dato nome di campo potrebbe verificarsi per valori più brevi più rapidamente o con probabilità più alta rispetto a valori più lunghi.

Questa mitigazione è più efficace tra due endpoint. Se i messaggi vengono ricodificati da un intermediario senza conoscenza di quale entità ha costruito un dato messaggio, l'intermediario potrebbe inavvertitamente unire contesti di compressione che l'encoder originale aveva specificamente mantenuto separati.

Nota: Semplicemente rimuovere le voci corrispondenti al campo dalla tabella dinamica può essere inefficace se l'attaccante ha un modo affidabile per far reinstallare i valori. Ad esempio, una richiesta per caricare un'immagine in un browser web include tipicamente il campo di header Cookie (un obiettivo potenzialmente molto prezioso per questo tipo di attacco), e i siti web possono facilmente forzare il caricamento di un'immagine, aggiornando così la voce nella tabella dinamica.

7.1.3 Letterali mai indicizzati (Never-Indexed Literals)

Le implementazioni possono anche scegliere di proteggere i campi sensibili non comprimendoli e invece codificando il loro valore come letterali.

Rifiutare di inserire una riga di campo nella tabella dinamica è efficace solo se ciò viene evitato su tutti gli hop. Il bit letterale mai indicizzato (vedere la sezione 4.5.4) può essere utilizzato per segnalare agli intermediari che un particolare valore è stato intenzionalmente inviato come letterale.

Un intermediario NON DEVE ricodificare un valore che utilizza una rappresentazione letterale con il bit 'N' impostato con un'altra rappresentazione che lo indicizzerebbe. Se QPACK viene utilizzato per la ricodifica, DEVE essere utilizzata una rappresentazione letterale con il bit 'N' impostato. Se HPACK viene utilizzato per la ricodifica, DEVE essere utilizzata la rappresentazione letterale mai indicizzata (vedere la sezione 6.2.3 di [RFC7541]).

La scelta di contrassegnare che un valore di campo non dovrebbe mai essere indicizzato dipende da diversi fattori. Poiché QPACK non protegge contro l'ipotesi di un intero valore di campo, i valori brevi o a bassa entropia sono più facilmente recuperati da un avversario. Pertanto, un encoder potrebbe scegliere di non indicizzare valori con bassa entropia.

Un encoder potrebbe anche scegliere di non indicizzare valori per campi che sono considerati altamente preziosi o sensibili al recupero, come i campi di header Cookie o Authorization.

Al contrario, un encoder potrebbe preferire indicizzare valori per campi che hanno poco o nessun valore se fossero esposti. Ad esempio, un campo di header User-Agent non varia comunemente tra le richieste ed è inviato a qualsiasi server. In tal caso, la conferma che un particolare valore User-Agent è stato utilizzato fornisce poco valore.

Si noti che questi criteri per decidere di utilizzare una rappresentazione letterale mai indicizzata evolveranno nel tempo man mano che nuovi attacchi vengono scoperti.

7.2 Codifica Huffman statica (Static Huffman Encoding)

Non esiste attualmente alcun attacco noto contro una codifica Huffman statica. Uno studio ha dimostrato che l'utilizzo di una tabella di codifica Huffman statica ha creato una perdita di informazioni; tuttavia, questo stesso studio ha concluso che un attaccante non poteva sfruttare questa perdita di informazioni per recuperare una quantità significativa di informazioni (vedere [PETAL]).

7.3 Consumo di memoria (Memory Consumption)

Un attaccante può provare a far esaurire la memoria a un endpoint. QPACK è progettato per limitare sia le quantità di memoria di picco che stabili allocate da un endpoint.

QPACK utilizza la definizione della dimensione massima della tabella dinamica e del numero massimo di stream bloccati per limitare la quantità di memoria che l'encoder può far consumare al decoder. In HTTP/3, questi valori sono controllati dal decoder tramite i parametri SETTINGS_QPACK_MAX_TABLE_CAPACITY e SETTINGS_QPACK_BLOCKED_STREAMS, rispettivamente (vedere la sezione 3.2.3 e la sezione 2.1.2). Il limite sulla dimensione della tabella dinamica tiene conto della dimensione dei dati memorizzati nella tabella dinamica, più una piccola tolleranza per l'overhead. Il limite sul numero di stream bloccati è solo un proxy per la quantità massima di memoria richiesta dal decoder. La quantità massima effettiva di memoria dipenderà da quanta memoria il decoder utilizza per tracciare ogni stream bloccato.

Un decoder può limitare la quantità di memoria di stato utilizzata per la tabella dinamica impostando un valore appropriato per la dimensione massima della tabella dinamica. In HTTP/3, questo si ottiene impostando un valore appropriato per il parametro SETTINGS_QPACK_MAX_TABLE_CAPACITY. Un encoder può limitare la quantità di memoria di stato che utilizza scegliendo una dimensione di tabella dinamica più piccola di quella consentita dal decoder e segnalando questo al decoder (vedere la sezione 4.3.1).

Un decoder può limitare la quantità di memoria di stato utilizzata per gli stream bloccati impostando un valore appropriato per il numero massimo di stream bloccati. In HTTP/3, questo si ottiene impostando un valore appropriato per il parametro SETTINGS_QPACK_BLOCKED_STREAMS. Gli stream che rischiano di bloccarsi non consumano memoria di stato aggiuntiva sull'encoder.

Un encoder alloca memoria per tracciare tutti i riferimenti alla tabella dinamica nelle sezioni di campo non riconosciute. Un'implementazione può limitare direttamente la quantità di memoria di stato utilizzando solo tanti riferimenti alla tabella dinamica quanti desidera tracciare; non è richiesta alcuna segnalazione al decoder. Tuttavia, limitare i riferimenti alla tabella dinamica ridurrà l'efficacia della compressione.

La quantità di memoria temporanea consumata da un encoder o decoder può essere limitata elaborando le righe di campo in sequenza. Un'implementazione del decoder non ha bisogno di conservare un elenco completo di righe di campo durante la decodifica di una sezione di campo. Un'implementazione dell'encoder non ha bisogno di conservare un elenco completo di righe di campo durante la codifica di una sezione di campo se utilizza un algoritmo a singolo passaggio. Si noti che potrebbe essere necessario per un'applicazione conservare un elenco completo di righe di campo per altri motivi; anche se QPACK non lo forza, i vincoli dell'applicazione potrebbero renderlo necessario.

Sebbene il limite negoziato sulla dimensione della tabella dinamica rappresenti gran parte della memoria che può essere consumata da un'implementazione QPACK, i dati che non possono essere inviati immediatamente a causa del controllo di flusso non sono influenzati da questo limite. Le implementazioni dovrebbero limitare la dimensione dei dati non inviati, specialmente sullo stream decoder dove la flessibilità di scegliere cosa inviare è limitata. Le possibili risposte a un eccesso di dati non inviati potrebbero includere la limitazione della capacità del peer di aprire nuovi stream, la lettura solo dallo stream encoder o la chiusura della connessione.

7.4 Limiti di implementazione (Implementation Limits)

Un'implementazione di QPACK deve garantire che valori grandi per gli interi, codifica lunga per gli interi o letterali di stringa lunghi non creino debolezze di sicurezza.

Un'implementazione deve impostare un limite per i valori che accetta per gli interi, così come per la lunghezza codificata; vedere la sezione 4.1.1. Allo stesso modo, deve impostare un limite alla lunghezza che accetta per i letterali di stringa; vedere la sezione 4.1.2. Questi limiti DOVREBBERO essere abbastanza grandi da elaborare il singolo campo più grande che l'implementazione HTTP può essere configurata per accettare.

Se un'implementazione incontra un valore più grande di quello che è in grado di decodificare, questo DEVE essere trattato come un errore di stream di tipo QPACK_DECOMPRESSION_FAILED se su uno stream di richiesta o un errore di connessione del tipo appropriato se sullo stream encoder o decoder.