GraphQL offre la flessibilità di richiedere esattamente le risorse e gli attributi necessari, niente di più e niente di meno. Questo a differenza di REST, che spesso esegue un over-fetching o un under-fetching dei dati. Questa precisione rende GraphQL altamente efficiente. Inoltre, GraphQL offre modi standard per gestire la paginazione, migliorando ulteriormente la sua flessibilità. Tuttavia, gli utenti malintenzionati possono sfruttare queste caratteristiche di GraphQL e ciò può comportare rischi significativi per la stabilità del server.
In questo blog esploreremo come la flessibilità di GraphQL possa essere usata contro di voi. Ci concentreremo in particolare su una vulnerabilità evidenziata dalla OWASP API Security Top 10: il consumo illimitato di risorse. Discuteremo anche i passi pratici per proteggere i vostri sistemi da questo tipo di abuso.
La risposta di GraphQL all'over-fetching e all'under-fetching
GraphQL è stato progettato in parte per risolvere i problemi di over-fetching che si incontrano normalmente con REST. Ad esempio, consideriamo un database di e-commerce standard con utenti, prodotti e ordini. Immaginiamo di dover recuperare l'importo totale in dollari di un ordine, dato l'ID dell'ordine. Con REST, la richiesta GET a /orders/17 non recupererebbe solo l'importo in dollari, ma anche quanto segue:
- dati dell'ordine
- informazioni sulla fatturazione
- informazioni sulla spedizione
- quantità di prodotto
- fiscale
- stato dell'ordine
- ... e altro ancora
Si tratta di un eccesso di raccolta.
Con REST, si verifica anche l'under-fetching, quando è necessario mettere insieme dati associati da più risorse. Si immagini di voler visualizzare un riepilogo con la data e lo stato di un ordine, i nomi e le descrizioni di tutti i prodotti presenti nell'ordine e il nome e l'e-mail dell'utente che ha effettuato l'ordine. Per farlo, è necessario inviare più richieste:
- GET /ordini/17
- GET /prodotti/1662527
- GET /prodotti/9914188
- GET /prodotti/3750021
- GET /prodotti/7557109
- GET /prodotti/6081142
- GET /utenti/3314
GraphQL è stata la risposta a queste carenze di REST. È possibile interrogare esattamente ciò di cui si ha bisogno, attraverso le risorse associate. Per ottenere quanto sopra, il GraphQL potrebbe essere simile a questo:
query { |
È così semplice e flessibile! Tuttavia, questo livello di flessibilità significa anche che un utente malintenzionato può deliberatamente sovrallocare i dati.
Abuso della flessibilità delle query
La sintassi di interrogazione di GraphQL consente di eseguire più query all'interno della stessa richiesta. Potremmo prendere la query di cui sopra e fare qualcosa di simile:
query { |
Questa volta abbiamo richiesto gli stessi dati della query precedente, solo che li abbiamo richiesti due volte. Naturalmente, la risposta sarà doppia rispetto alla richiesta singola. Tuttavia, cosa succederebbe se ripetessimo la query 100 volte in un'unica richiesta?
query { |
In questo modo, abbiamo creato una query che produrrà una risposta 100 volte più grande della nostra query originale. Un buon modo per illustrare questo attacco è la seguente immagine di cheeseburger. I panini per hamburger formano la singola richiesta, ma tra i panini potrebbero esserci centinaia di polpette di manzo!
Se un utente malintenzionato dovesse abusare di questa flessibilità di interrogazione, il consumo eccessivo di risorse potrebbe soffocare il vostro server.
Abuso delle funzioni di paginazione
GraphQL ha anche alcuni modi standard per gestire la paginazione. Un approccio comune è la paginazione basata sull'offset, in cui il chiamante fornisce il numero di elementi da recuperare (limite) e l'elemento da cui iniziare (offset).
Ad esempio, una query per restituire informazioni da una ricerca di prodotti potrebbe essere simile a questa:
query { |
E se modificassimo i parametri di paginazione per eseguire invece questa query?
query { |
In una serie di esempi simili che ho testato su un sito di e-commerce, ho confrontato le risposte ricevute:
$ du response*.json |
Si potrebbe pensare che il file grande sia circa 100 volte più grande di quello piccolo, dato che il limite è stato impostato su 800 invece che su 8. Probabilmente la ricerca non ha prodotto 800 risultati in totale (forse solo 16-20).
L'abuso della paginazione è un altro esempio di come qualcuno potrebbe manipolare i parametri delle query GraphQL per aggiungere carico al vostro server. Sfruttando questa funzione, gli aggressori possono costringere il server a gestire richieste molto più grandi di quelle previste, portando potenzialmente all'esaurimento delle risorse e alla negazione del servizio (DoS).
OWASP API4:2023 Consumo di risorse senza restrizioni
Ciò che abbiamo dimostrato rientra nella OWASP API Security Top 10, in particolare API4:2023 Unrestricted Resource Consumption. Questa vulnerabilità si verifica quando le API non limitano alcuni tipi di interazioni o richieste, lasciando il server vulnerabile ad attacchi DoS e ad altre interruzioni operative.
Quando un'API consente un'interrogazione eccessiva o una paginazione senza limiti, il consumo di risorse può aumentare vertiginosamente. Questo a sua volta può causare un degrado delle prestazioni o addirittura un guasto completo del server. Senza limiti adeguati, questi attacchi possono interrompere il servizio. Potreste incorrere in costi operativi elevati, vedere i clienti allontanarsi e perdere l'attività.
Come proteggersi
Per far fronte a questi rischi, è necessario regolare adeguatamente le richieste API. Implementate controlli che limitino la quantità di dati che possono essere richiesti. Ciò include l'impostazione di limiti sulla dimensione e sul numero di query, nonché l'implementazione della limitazione della velocità e di altre misure di protezione.
Ecco alcuni suggerimenti pratici per proteggersi:
- Limiti alle dimensioni del payload di richieste e risposte: Impostando limiti alle dimensioni dei dati che possono essere richiesti e restituiti, si può evitare che query troppo grandi sovraccarichino il server.
- Limiti di paginazione: Implementare un limite massimo per la paginazione, assicurando che il chiamante non cerchi di recuperare più record di quanto sia ragionevole.
- Web Application Firewall (WAF): Un WAF può aiutare a rilevare e bloccare le attività dannose, sventando potenziali attacchi all'API GraphQL. Considerate l'uso di un WAF come Haltdos di Linode Marketplace per aggiungere questo ulteriore livello di sicurezza.
- Strumenti di sicurezza per le API: Gli strumenti in grado di rilevare e ridurre le attività dannose sono essenziali. Possono aiutare a identificare schemi insoliti che potrebbero indicare un attacco, consentendo di intervenire prima che il sistema venga colpito.
Adottando queste misure, è possibile ridurre in modo significativo il rischio di sfruttare il server GraphQL attraverso un consumo eccessivo di risorse. Garantire che le interazioni con le API siano regolate in modo appropriato contribuirà a mantenere la stabilità e le prestazioni del server.
Per ulteriori informazioni sulla costruzione con GraphQL, consultare GraphQL Apollo: An Introduction with Examples nei nostri documenti.
Commenti