コンテンツにスキップ

Brute Force Login Using Alias Batching in GraphQL API

GraphQL APIでのエイリアスバッチ処理を使用したブルートフォースログイン

概要

GraphQLにおけるエイリアスバッチ処理を使用したブルートフォースログインとは、攻撃者がエイリアス機能を利用してログイン試行を自動化し、単一のクエリで多数の認証情報の組み合わせを簡単に送信できるようにする攻撃です。

GraphQLでは、エイリアスを使用すると、クライアントは同じクエリの複数のバージョンを異なる名前で送信できます。攻撃者は、試行ごとに異なるエイリアス名を使用して、単一のクエリ内でログインリクエストをバッチ処理することでこれを悪用します。これにより、従来のレート制限による保護を回避し、ログイン試行で認証システムを圧倒する、効率的なブルートフォース攻撃につながる可能性があります。

例:

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

推奨事項

エイリアスバッチ処理を使用したブルートフォースログイン攻撃のリスクを軽減するには、次の対策の実装を検討してください。

  • エイリアスの制限:単一のGraphQLクエリで許可されるエイリアスの数にサーバー側の制限を構成します。GraphQL Armorなどのツールを設定して、エイリアスを制限し、過負荷を防ぐことができます。

  • CAPTCHAの実装:CAPTCHAまたはその他のユーザー検証メカニズムを導入して、一定回数ログインに失敗した後にユーザーにチャレンジを提示し、保護レイヤーを追加します。

  // 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()

リンク

基準

  • 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
  • HIPAA_CONTROLS:
    • SECURITY221
    • SECURITY212
    • SECURITY213