Comment empêchez-vous les attaques imbriquées sur le serveur GraphQL / Apollo?

Comment empêcher une attaque imbriquée contre un serveur Apollo avec une requête telle que:

{
  authors {
    firstName
    posts {
      title
      author {
        firstName
        posts{
          title
          author {
            firstName
            posts {
              title
              [n author]
                [n post]
            }
          }
        }
      }
    }
  }
}

En d'autres termes, comment pouvez-vous limiter le nombre de récurrences soumise dans une requête? Cela pourrait être une vulnérabilité potentielle du serveur.

40
demandé sur rdrey 2016-05-20 06:29:53

4 réponses

Au moment de l'écriture, il n'y a pas de fonctionnalité intégrée dans GraphQL-js ou Apollo Server pour gérer cette préoccupation, mais c'est quelque chose qui devrait certainement avoir une solution simple car GraphQL devient plus populaire. Ce problème peut être résolu avec plusieurs approches à plusieurs niveaux de la pile, et devrait également toujours être combiné avec la limitation de débit, de sorte que les gens ne puissent pas envoyer trop de requêtes à votre serveur (c'est aussi un problème potentiel avec REST).

Je vais juste énumérer tout les différentes méthodes auxquelles je peux penser, et je vais essayer de garder cette réponse à jour car ces solutions sont implémentées dans divers serveurs GraphQL. Certains d'entre eux sont assez simples, et certains sont plus complexes.

  1. Query validation : dans chaque serveur GraphQL, la première étape pour exécuter une requête est validation - c'est là que le serveur essaie de déterminer s'il y a des erreurs graves dans la requête, afin que nous puissions éviter d'utiliser les ressources réelles du serveur si nous pouvons trouver cela il y a une erreur de syntaxe ou un argument invalide à l'avant. GraphQL-JS est livré avec une sélection de règles par défaut qui suivent un format assez similaire à ESLint. Tout comme il existe une règle pour détecter cycles infinis en fragments , on pourrait écrire une règle de validation pour détecter les requêtes avec trop d'imbrication et les rejeter au stade de la validation.
  2. Délai D'attente de la requête : S'il n'est pas possible de détecter qu'une requête consomme trop de ressources statiquement (peut-être même les requêtes superficielles peuvent être très coûteuses!), alors nous pouvons simplement ajouter un délai d'attente à l'exécution de la requête. Cela a quelques avantages: (1) c'est une limite difficile qui n'est pas trop difficile à raisonner, et (2) cela aidera également dans les situations où l'un des backends prend excessivement longtemps pour répondre. Dans de nombreux cas, un utilisateur de votre application préférez un champ manquant plus d'attendre 10 secondes pour obtenir une réponse.
  3. Query whitelisting : c'est probablement la méthode la plus impliquée, mais vous pourriez compilez une liste des requêtes autorisées à l'avance et vérifiez toutes les requêtes entrantes par rapport à cette liste. Si vos requêtes sont totalement statiques (vous ne faites aucune génération de requête dynamique sur le client avec quelque chose comme Relay), c'est l'approche la plus fiable. Vous pouvez utiliser un outil automatisé pour extraire des chaînes de requête de vos applications lorsqu'elles sont déployées, de sorte que dans le développement, vous écrivez toutes les requêtes que vous voulez, mais en production, seules celles que vous voulez sont laissées. Un autre avantage de cette approche est-ce que vous pouvez ignorer entièrement la validation de la requête, puisque vous savez que toutes les requêtes possibles sont déjà valides. Pour plus d'avantages des requêtes statiques et des listes blanches, lisez cet article: https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a
  4. limitation des coûts de requête : (ajouté dans une édition) similaire aux délais d'attente de requête, vous pouvez affecter un coût à différentes opérations lors de l'exécution de la requête, par exemple une requête de base de données, et limiter le coût total du client est en mesure d'utiliser par requête. Cela peut être combiné avec la limitation du parallélisme maximal d'une seule requête, de sorte que vous pouvez empêcher le client d'envoyer quelque chose qui initie des milliers de requêtes parallèles à votre backend.

(1) et (2) en particulier sont probablement quelque chose que chaque serveur GraphQL devrait avoir par défaut, d'autant plus que de nombreux nouveaux développeurs pourraient ne pas être au courant de ces préoccupations. (3) ne fonctionnera que pour certains types d'applications, mais pourrait être un bon choix quand il sont des exigences de performance ou de sécurité très strictes.

39
répondu stubailo 2016-11-18 06:29:51

Pour compléter le point (4) dans la réponse de stubailo, voici quelques nœuds.implémentations js qui imposent limites de coût et de profondeur sur les documents GraphQL entrants.

Ce sont des règles personnalisées qui complètent la phase de validation.

8
répondu Andy Carlson 2017-08-09 23:57:01

Une variante de la liste blanche de requête est signature de requête .

Pendant le processus de construction, chaque requête est signée cryptographiquement à l'aide d'un secret partagé avec le serveur mais non fourni avec le client. Ensuite, lors de l'exécution, le serveur peut valider qu'une requête est authentique.

L'avantage par rapport à la liste blanche est que l'écriture de requêtes dans le client ne nécessite aucune modification du serveur. Ceci est particulièrement utile si plusieurs clients accèdent au même serveur (par exemple web, de bureau et applications mobiles).

1
répondu Tamlyn 2017-11-29 16:04:42

Pour la Requête coût limiter vous pouvez utiliser graphql-l'analyse des coûts

Il s'agit d'une règle de validation qui analyse la requête avant de l'exécuter. Dans votre serveur GraphQL, il vous suffit d'attribuer une configuration de coût pour chaque champ de votre carte de type de schéma que vous voulez.

1
répondu Schrax 2018-01-09 10:30:16