Vai al contenuto principale
BlogCalcoloDifendere il server GraphQL da un consumo eccessivo di risorse

Difendere il server GraphQL da un consumo eccessivo di risorse

Difendi_il_tuo_server_GraphQL_dal_consumo_eccessivo_di_risorse (2)

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 {
  order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

È 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 {
  Q1: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
  Q2: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

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 {
  Q00: order(id: "17") {    …  }  Q01: order(id: "17") {    …  }  …  Q99: order(id: "17") {    …  }
}

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!

Domanda farcita

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 {
  products(searchString: "shirt", limit: 8, offset: 0) {
    id
    name
    description
    sku
    category
    images {
      path
      alt_text
    }
    variations {
      name
      description
      cost
    }
  }
}

E se modificassimo i parametri di paginazione per eseguire invece questa query?

query {
  products(searchString: "shirt", limit: 800, offset: 0) {    …  }}

In una serie di esempi simili che ho testato su un sito di e-commerce, ho confrontato le risposte ricevute:

$ du response*.json
680496  response_big.json
333649  response_small.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

Lascia una risposta

Il vostro indirizzo e-mail non sarà pubblicato. I campi obbligatori sono contrassegnati da *