コンテンツにスキップ

Directive Overloading in GraphQL API

GraphQL APIにおけるディレクティブのオーバーロード

説明

GraphQLにおけるディレクティブのオーバーロードは、攻撃者がクエリ内で大量のディレクティブを利用して、サーバーの処理能力を圧迫した場合に発生します。

GraphQLのディレクティブはクエリの動作を変更するために使用されますが、過度に使用するとサーバーリソースが枯渇し、サービス拒否(DoS)攻撃につながる可能性があります。この種の攻撃は、パフォーマンスの低下や完全なサービス停止を引き起こす可能性があります。

例:

query oxo {
  __typename @aa @aa @aa @aa @aa @aa @aa @aa @aa @aa
}

ディレクティブのオーバーロードによるセキュリティ上の影響は、以下の問題につながる可能性があります。

  • サービス拒否(DoS): 単一のクエリで過剰な数のディレクティブを送信することにより、攻撃者はサーバーに過負荷をかけ、正規のユーザーに対して応答の遅延やサービス停止を経験させる可能性があります。
  • リソース枯渇: サーバーはディレクティブの解析と検証に大量の計算リソースを使用する場合があり、これによりメモリの枯渇やCPUのスパイクが発生する可能性があります。
  • システムの利用不可: 放置すると、ディレクティブのオーバーロード攻撃によって、すべてのユーザーがGraphQLサービスを利用できなくなる可能性があります。

推奨事項

ディレクティブのオーバーロード攻撃のリスクを軽減するために、以下の対策を講じることができます。

  • タイムアウトの実装: 解決に時間がかかりすぎるクエリを「キル(kill)」するためのタイムアウトの実装は、非常に効果的です。最大実行時間を設定することで、この制限を超えるクエリを自動的に終了させ、サーバーリソースの過度な消費を防ぐことができます。

  • ディレクティブの制限: 単一のGraphQLクエリで許可されるディレクティブの数にサーバー側の制限を実装します。GraphQL Armorのようなツールを構成してディレクティブを制限し、過負荷を防ぐことができます。

// Configuring for GraphQL Armor
GraphQLArmorConfig({
  maxDirectives: {
    // Toggle the plugin | default: true
    enabled?: boolean,

    // Directives threshold | default: 50
    n?: int,

    // Callbacks that are ran whenever a Query is accepted
    onAccept?: GraphQLArmorAcceptCallback[],

    // Callbacks that are ran whenever a Query is rejected
    onReject?: GraphQLArmorRejectCallback[],

    // Do you want to propagate the rejection to the client? | default: true
    propagateOnRejection?: boolean,
  }
})
import graphql
from graphql.language import ast
from graphql.language import parser
from settings import api

def validate_directives(query: str) -> None:
    """
    This validation prevents the execution of queries containing an excessive
    amount of directives to prevent abuse.
    """

    class DirectivesParser(parser.Parser):
        def parse_directives(self, is_const: bool) -> list[ast.DirectiveNode]:
            directives = 0
            while self.peek(graphql.TokenKind.AT):
                directives += 1
                if directives > api.API_MAX_DIRECTIVES:
                    raise graphql.GraphQLError("Exception - Max directives exceeded")
                self.parse_directive(is_const)
            return []

    ast_parser = DirectivesParser(query)
    ast_parser.parse_document()

リンク

標準

  • 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