Sto rispondendo alla mia stessa domanda perché credo ora capisco BREAK e come prevenirlo. Mi piacerebbe un feedback.
Funzionamento di BREACH (a quanto ho capito)
(Espansione su una spiegazione qui che mi ha aiutato.)
Supponi di essere un attaccante. Hai effettuato l'accesso a un servizio come te stesso. Si nota che esiste un endpoint search
e se si invia il termine di ricerca rabbits
, si ottiene una risposta come questa:
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>rabbits</SearchTerm>
<Results>
<Result>rabbits rock</Result>
<Result>yay rabbits</Result>
</Results>
</SearchResponse>
Noterai anche che la risposta è gzip e crittografata (HTTPS).
Prova a cercare una stringa formattata come <AuthToken
, come aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
. La risposta è:
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</SearchTerm>
<Results>
</Results>
</SearchResponse>
Non ci sono risultati per questo. Quindi modifica leggermente il termine di ricerca:
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>d2a37aaaaaaaaaaaaaaaaaaaaaaaaaa</SearchTerm>
<Results>
</Results>
</SearchResponse>
Come speravi, sta accadendo qualcosa di interessante. Poiché il termine di ricerca non ha senso, <Results>
è sempre lo stesso: vuoto. L'unica cosa chaing è <SearchTerm>
. A causa della compressione, più il valore <SearchTerm>
assomiglia al valore <AuthToken>
, più piccola è la risposta.
Questo è il modo in cui funziona la compressione gzip: rimuove la ripetizione durante la compressione e la ripristina durante la decompressione. Più l'input è ripetitivo, più piccolo viene compresso.
Cerca di nuovo, utilizzando il valore esatto di <AuthToken>
.
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>d2a372efa35aab29028c49d71f56789</SearchTerm>
<Results>
</Results>
</SearchResponse>
Questa volta prendi nota di quanto sia piccola la risposta.
Ora, poiché queste sono le tue richieste, sei stato in grado di leggerle direttamente. Se si potesse fare un attacco MITM su un altro utente del sito (ad esempio, eseguendo un router canaglia), si sarebbe in grado di vedere la dimensione della risposta crittografata, ma non i contenuti effettivi.
Pensi a te stesso: se posso ingannare qualcun altro nell'invio dei termini di ricerca li voglio, e se riesco a vedere quanto è grande la risposta crittografata, posso modificare il termine di ricerca più e più volte. Più mi avvicino a indovinare il token auth, più piccola sarà la risposta, e quando è la dimensione della risposta che ho appena visto, ho indovinato correttamente. Una volta che conosco il loro token di autenticazione, posso accedere come loro.
Se puoi in qualche modo eseguire un attacco XSS sulla tua vittima, puoi farli fare le richieste necessarie.
Mitigazione
Questo attacco non funzionerebbe se:
- Il server non ha utilizzato la compressione HTTP (come gzip, nel nostro esempio)
- La richiesta non può essere eseguita correttamente senza un token CSRF, che l'utente malintenzionato non può sapere
- Il server non inserisce mai entrambi dati sensibili (come un token API) e dati forniti dall'utente (come il termine di ricerca) nella stessa risposta
- Il server non ha mai restituito lo stesso token dell'API due volte (ad esempio, se i valori dei token grezzi sono stati timestampati e firmati prima dell'invio, il timestamp garantisce che il token nella risposta sia costantemente modificato)
- La risposta conteneva sempre un riempimento a caso, come indicato da @AndrolGenhald in un commento (sebbene con richieste sufficienti, un utente malintenzionato potrebbe separare il segnale da questo rumore)