Skip to content

Brute Force Login Using Alias Batching in GraphQL API

Brute Force Login Using Alias Batching in GraphQL API

Description

Brute Force Login Using Alias Batching in GraphQL involves an attacker leveraging the alias feature to automate login attempts, making it easier to submit numerous credential combinations in a single query.

In GraphQL, aliases allow clients to send multiple versions of the same query under different names. Attackers exploit this by batching login requests within a single query using different alias names for each attempt. This can lead to an efficient brute force attack, bypassing traditional rate-limiting protections and overwhelming the authentication system with login attempts.

Example:

query loginBatch {
  login1: login(username: "user1", password: "password1") { token }
  login2: login(username: "user2", password: "password2") { token }
  login3: login(username: "user3", password: "password3") { token }
  ...
}

Recommendation

To mitigate the risk of Brute Force Login Using Alias Batching attacks, consider implementing the following measures:

  • Limit Aliases: Configure server-side limits on the number of aliases allowed in a single GraphQL query. You can configure tools like GraphQL Armor to limit aliases and prevent overloading.

  • Implement CAPTCHA: Introduce CAPTCHA or other user verification mechanisms to challenge users after a certain number of failed login attempts, adding an additional layer of protection.

  // Configuring rate limiting and alias limits for a GraphQL server
  const express = require('express');
  const rateLimit = require('express-rate-limit');
  const { ApolloServer, gql } = require('apollo-server-express');
  const { GraphQLArmorConfig } = require('graphql-armor');

  const app = express();

  // Rate limit for login attempts
  const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 5, // limit each IP to 5 requests per windowMs
    message: "Too many login attempts, please try again later."
  });

  // Define your GraphQL schema
  const typeDefs = gql`
    type Query {
      login(username: String!, password: String!): String
    }
  `;

  // Implement the alias limit configuration
  GraphQLArmorConfig({
    maxAliases: {
      enabled: true,
      n: 20, // Set the maximum number of aliases allowed per query
      onAccept: [],
      onReject: [],
      propagateOnRejection: true,
    }
  });

  const server = new ApolloServer({ typeDefs, resolvers });

  // Apply rate limiter middleware
  app.use('/graphql', loginLimiter);

  server.applyMiddleware({ app });

  app.listen({ port: 4000 }, () =>
    console.log(`Server ready at http://localhost:4000${server.graphqlPath}`)
  );
  import graphql
  from graphql.language import ast
  from graphql.language import parser
  from settings import api

  def validate_aliases(query: str) -> None:
      """
      This validation prevents the execution of queries containing an excessive
      number of aliases to prevent server overload.
      """
      class AliasesParser(parser.Parser):
          def parse_aliases(self) -> list[ast.FieldNode]:
              aliases = 0
              while self.peek(graphql.TokenKind.NAME):
                  aliases += 1
                  if aliases > api.API_MAX_ALIASES:
                      raise graphql.GraphQLError("Exception - Max aliases exceeded")
                  self.parse_field()
              return []

      ast_parser = AliasesParser(query)
      ast_parser.parse_document()

Standards

  • PCI_STANDARDS:
    • REQ_6_2
    • REQ_6_4
    • REQ_11_3
  • 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