Secure Steady
GraphQL の脆弱性と対策 - GraphQL セキュリティ の使い方・オプション・サンプル

GraphQL の脆弱性と対策 - GraphQL セキュリティ

GraphQL API 固有のセキュリティリスクと対策。イントロスペクション漏洩・過剰取得・バッチ攻撃・認可バイパスなどを解説。

概念図

GraphQL セキュリティ diagram

攻撃シナリオ

スキーマ全体を取得し、非公開フィールドや型を発見する

bash
# イントロスペクション攻撃
{
  __schema {
    types {
      name
      fields { name type { name } }
    }
  }
}

深いネストでサーバーリソースを枯渇させる

bash
# ネストによる DoS
query {
  users {
    posts {
      comments {
        author {
          posts {
            comments { ... }
          }
        }
      }
    }
  }
}

GraphQL のセキュリティリスク

GraphQL は柔軟なクエリ言語ですが、REST API とは異なるセキュリティ上の課題があります。

リスク 説明
イントロスペクション漏洩 __schema クエリでAPI の全体構造(型・フィールド・リレーション)が露出する
過剰なデータ取得 クライアントが任意のフィールドを要求でき、意図しないデータが返される
深いネスト / 循環クエリ 再帰的なリレーションを辿る深いクエリでサーバーを過負荷にする(DoS)
バッチ攻撃 1 リクエストに複数クエリを詰め込み、レート制限を回避する
認可バイパス フィールド単位・オブジェクト単位の認可チェックが漏れやすい
インジェクション 引数を直接 SQL やシェルに渡すと SQL インジェクション等が成立する

イントロスペクションの制御

本番環境では必ずイントロスペクションを無効化してください。

イントロスペクションが有効なままだと、攻撃者は API の全フィールド・型・リレーションを把握できます。

これは攻撃面の調査(リコン)を劇的に容易にします。

# Apollo Server
new ApolloServer({
  introspection: false, // 本番では false
});

# Yoga / Envelop
useDisableIntrospection()

開発環境だけで有効にするには、環境変数で切り替えます。

クエリの深さ・コスト制限

GraphQL では 1 つのクエリで大量のデータを取得できるため、クエリの複雑さを制限する仕組みが不可欠です。

手法 説明
深さ制限 ネストの最大深度を設定(例: 最大 5 レベル)
コスト分析 フィールドごとにコストを割り当て、合計が上限を超えるクエリを拒否
タイムアウト クエリの実行時間に上限を設定
ページネーション強制 first / last 引数なしのリスト取得を禁止
# graphql-depth-limit (Node.js)
import depthLimit from 'graphql-depth-limit';

new ApolloServer({
  validationRules: [depthLimit(5)],
});

認可の実装

GraphQL ではリゾルバ単位で認可チェックを実装する必要があります。

REST のようにエンドポイント単位ではなく、フィールド単位で制御するのがポイントです。

  • ディレクティブベース: @auth(role: "admin") のようなカスタムディレクティブでフィールドを保護
  • ミドルウェア / シールド: GraphQL Shield 等のライブラリで宣言的にルールを定義
  • DataLoader パターン: N+1 問題の解決と同時に、ロード時に権限チェックを挟む

注意: 認証(誰であるか)と認可(何ができるか)を混同しない

JWT で認証しても、各フィールドへのアクセス権限は別途チェックが必要です。

その他の対策

  • Persisted Queries(永続化クエリ): 事前に登録したクエリのみ受け付け、任意クエリの実行を防止する。最も効果的な対策の一つ
  • レート制限: IP 単位だけでなく、クエリの複雑さも考慮したレート制限を導入する
  • フィールドレベルのマスキング: ユーザーのロールに応じて特定のフィールドを null にする、またはスキーマから除外する
  • エラーメッセージの制御: スタックトレースや内部情報がエラーレスポンスに含まれないようにする
  • ロギングと監視: 異常なクエリパターン(深いネスト、大量バッチ)を検知してアラートを出す

関連トピック