コンテンツにスキップ

Array-Based Batch Queries

配列ベースのバッチクエリ

概要

GraphQLにおける配列ベースのバッチクエリは、攻撃者が配列構造を使用して単一のリクエストで複数のクエリを送信する場合に発生し、サーバーの処理能力を過負荷にする可能性があります。

GraphQLでは、クライアントは通常、リクエストごとに1つのクエリを送信することが許可されています。しかし、適切に制限されていない場合、攻撃者は配列を使用して複数のクエリを単一のリクエストにまとめることができます。これにより、過剰なサーバーリソースが消費され、パフォーマンスが低下したり、サービスが停止したりするDoS(サービス拒否)攻撃につながる可能性があります。

例:

[
  { query: "{ user(id: 1) { name } }" },
  { query: "{ user(id: 2) { name } }" },
  { query: "{ user(id: 3) { name } }" }
]

配列ベースのバッチクエリによるセキュリティへの影響:

サービス拒否(DoS): 攻撃者は単一のリクエストでクエリの大規模なバッチを送信し、サーバーに多数の操作を同時に処理させることができます。これにより、リソースが枯渇し、サービスがクラッシュする可能性があります。 リソースの枯渇: フィールドの重複と同様に、配列ベースのバッチクエリは、単一の呼び出しで大量のクエリによってサーバーを過負荷にし、CPUとメモリの使用量を急増させる可能性があります。 サービスの中断: 放置すると、配列ベースのバッチクエリにより、正規のユーザーがGraphQL APIを利用できなくなり、システムのダウンタイムやパフォーマンスの低下を引き起こす可能性があります。

推奨事項

複数のクエリが単一のリクエストにまとめられるGraphQLにおける配列ベースのバッチクエリ攻撃のリスクを軽減するために、次の戦略を適用できます。

  • クエリの複雑さの制限を実装する:単一のリクエストで処理されるクエリの数を考慮したルールを設定します。これにより、サーバーへの負荷が制限され、攻撃者が過度に大規模なクエリのバッチを送信するのを防ぎます。
  • リクエストごとのクエリ数を制限する:単一のバッチで送信できるクエリの数にサーバー側の制限を適用します。GraphQL Armorなどのツールは、制限を課し、配列ベースのバッチクエリによるリソースの過負荷を防ぐのに役立ちます。
  // Configuring for GraphQL Armor
  GraphQLArmorConfig({
      maxBatchQueries: {
          // Enable or disable the plugin | default: true
          enabled: true,

          // Set the maximum number of queries allowed per request | default: 5
          n: 5,

          // Callbacks to execute when a query batch is accepted
          onAccept: [],

          // Callbacks to execute when a query batch is rejected
          onReject: [],

          // Propagate rejection details to the client | default: true
          propagateOnRejection: true,
      }
  });
  import graphql
  from graphql.language import ast
  from graphql.language import parser
  from settings import api

  def validate_batch_queries(query: str) -> None:
      """
      This validation prevents the execution of requests containing excessive
      batch queries to avoid overloading the server.
      """
      class BatchQueryParser(parser.Parser):
          def parse_batch_queries(self) -> list[ast.OperationDefinitionNode]:
              query_count = 0
              while self.peek(graphql.TokenKind.BRACKET_L):
                  self.parse_operation_definition()
                  query_count += 1
                  if query_count > api.API_MAX_BATCH_QUERIES:
                      raise graphql.GraphQLError("Exception - Max batch queries exceeded")
              return []

      ast_parser = BatchQueryParser(query)
      ast_parser.parse_document()

リンク

基準

  • CWE_TOP_25:
    • CWE_20
  • PCI_STANDARDS:
    • REQ_6_2
    • REQ_6_4
    • REQ_11_3
  • OWASP_MASVS_L2:
    • MSTG_PLATFORM_2
  • OWASP_ASVS_L2:
    • V5_3_3
    • V5_3_4
    • V9_1_1
    • V12_1_1
    • V12_1_2
  • OWASP_ASVS_L3:
    • V5_3_3
    • V5_3_4
    • V12_1_1
    • V12_1_2
    • V12_1_3
  • 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