Aller au contenu

GraphQL Circular References

Références circulaires GraphQL

Description

GraphQL permet aux clients de demander des données spécifiques, et sa flexibilité peut être exploitée pour créer des requêtes complexes ou récursives. Des références circulaires se produisent lorsqu'un type d'objet se réfère à lui-même directement ou indirectement par l'intermédiaire d'autres types.

Par exemple :

 query CircularReferences  {
     user {
       friends {
         user {
           friends {
             user {
               __typename
             }
           }
         }
       }
     }
   }

Impact sur la sécurité des références circulaires dans GraphQL :

  • Déni de service : En envoyant une requête volumineuse avec trop de références imbriquées, un attaquant peut surcharger le serveur, ce qui le ralentit ou le fait planter.
  • Épuisement des ressources : Le serveur peut manquer de ressources mémoire ou processeur lors du traitement de la requête, ce qui entraîne une dégradation des performances ou une indisponibilité du service.

Recommandation

Pour atténuer le risque de références circulaires dans GraphQL, vous pouvez suivre ces recommandations : 1. Limitation de la profondeur : Implémentez un middleware pour vérifier la profondeur de la requête et déclencher une erreur si elle dépasse la limite. Exemple :

class DepthAnalysisMiddleware:
    def resolve(self, next, root, info, **args):
        if info.operation.selection_set:
            depth = 0
            for field in info.operation.selection_set.selections:
                depth = max(depth, self._get_depth(field))
            if depth > 3:
                raise Exception('Query depth is too high')
        return next(root, info, **args)

    def _get_depth(self, field):
        if field.selection_set:
            return 1 + max(self._get_depth(f) for f in field.selection_set.selections)
        return 1
  1. Détection de référence circulaire : Repensez le schéma pour éviter les références circulaires. Exemple de référence circulaire :
class User(graphene.ObjectType):
    id = graphene.ID()
    name = graphene.String()
    friends = graphene.List(lambda: User)

    def resolve_friends(self, info):
        return [User(id=1, name='Alice'), User(id=2, name='Bob')]

Exemple de schéma repensé :

  class FriendProfile(graphene.ObjectType):
      id = graphene.ID()
      name = graphene.String()

  class User(graphene.ObjectType):
      id = graphene.ID()
      name = graphene.String()
      friends = graphene.List(FriendProfile)

      def resolve_friends(self, info):
          return [FriendProfile(id=1, name='Alice'), FriendProfile(id=2, name='Bob')]
      const FriendProfile = new GraphQLObjectType({
          name: 'FriendProfile',
          fields: {
              id: { type: GraphQLID },
              name: { type: GraphQLString }
          }
      });

      const User = new GraphQLObjectType({
          name: 'User',
          fields: {
              id: { type: GraphQLID },
              name: { type: GraphQLString },
              friends: { type: new GraphQLList(FriendProfile) }
          }
      });  

Liens

Normes

  • CWE_TOP_25:
    • CWE_400
  • PCI_STANDARDS:
    • REQ_6_2
    • REQ_6_4
    • REQ_11_3
  • OWASP_MASVS_L2:
    • MSTG_PLATFORM_2
  • OWASP_ASVS_L3:
    • V13_4_1
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
    • CC_9_1
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213