GraphQL の脆弱性と対策 - GraphQL セキュリティ
GraphQL API 固有のセキュリティリスクと対策。イントロスペクション漏洩・過剰取得・バッチ攻撃・認可バイパスなどを解説。
概念図
攻撃シナリオ
スキーマ全体を取得し、非公開フィールドや型を発見する
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にする、またはスキーマから除外する - エラーメッセージの制御: スタックトレースや内部情報がエラーレスポンスに含まれないようにする
- ロギングと監視: 異常なクエリパターン(深いネスト、大量バッチ)を検知してアラートを出す
関連トピック
SQL インジェクション- ユーザー入力を通じて不正な SQL 文を実行させる攻撃。データの漏洩・改ざん・削除が可能になる。 CORS(オリジン間リソース共有)- 異なるオリジン間での HTTP リクエストを制御する仕組み。同一オリジンポリシーを緩和しつつ、不正なアクセスを防ぐ。 JWT(JSON Web Token)- JSON ベースのトークン形式。署名により改ざんを検知できるが、適切に運用しないとセキュリティリスクになる。 セッション管理- ユーザーの認証状態を維持する仕組み。セッション固定攻撃やセッションハイジャックへの対策が重要。 セキュアコーディングの基本- 安全なコードを書くための基本原則。入力検証・最小権限・エラーハンドリングの3原則で大半の脆弱性を防止できる。 