GraphQLは、必要なリソースと属性を正確にリクエストする柔軟性を提供する。これは、データを過剰にフェッチしたり過小にフェッチしたりすることが多いRESTとは異なります。この正確さにより、GraphQLは非常に効率的です。さらに、GraphQLはページネーションを処理する標準的な方法を提供し、その柔軟性をさらに高めています。しかし、悪意のあるユーザーはこれらのGraphQL機能を悪用することができ、サーバーの安定性に重大なリスクをもたらす可能性があります。
このブログでは、GraphQLの柔軟性がどのように悪用されるかを探ります。特に、OWASP API Security Top 10で強調された脆弱性、すなわち無制限のリソース消費に焦点を当てます。また、この種の悪用からシステムを保護するための実践的なステップについても説明します。
オーバーフェッチとアンダーフェッチに対するGraphQLの答え
GraphQLは、私たちが通常RESTで遭遇するオーバーフェッチの問題に対処するために設計されました。例えば、ユーザー、商品、注文を持つ標準的なeコマースデータベースを考えてみましょう。注文IDで指定された注文の合計金額をフェッチする必要があるとします。RESTでは、/orders/17へのGETリクエストは、ドル金額だけでなく、以下の内容もフェッチすることになる:
- 注文データ
- 課金情報
- 配送情報
- 製品数量
- 税金
- 注文状況
- ... and more
それはオーバーフェッチだ。
RESTでは、複数のリソースから関連するデータをまとめる必要がある場合、フェッチ不足も発生します。注文の日付とステータス、注文したすべての商品の名前と説明、注文したユーザーの名前とEメールを含むサマリーを表示したいとします。これを行うには、複数のリクエストを送信する必要があります:
- GET /orders/17
- GET /products/1662527
- GET /products/9914188
- GET /products/3750021
- GET /products/7557109
- GET /products/6081142
- GET /users/3314
こうしたRESTの欠点に対する答えがGraphQLだった。関連するリソースを横断して、必要なものを正確に問い合わせることができる。上記を達成するために、あなたのGraphQLは以下のようになるかもしれない:
query { |
とてもシンプルで柔軟だ!しかし、このレベルの柔軟性は、悪意のあるユーザーが意図的にデータを過剰にフェッチできることも意味する。
クエリの柔軟性を悪用する
GraphQLのクエリー構文では、同じリクエスト内で複数のクエリーを実行できる。上記のクエリを例にとると、次のようになります:
query { |
今回は、前回のクエリと同じデータをリクエストした。当然、レスポンスは1回のリクエストの2倍のサイズになる。しかし、1回のリクエストで100回クエリーを繰り返したらどうなるでしょうか?
query { |
このように、元のクエリの100倍のサイズのレスポンスを返すようなクエリを作ってしまったのだ。この攻撃を説明するには、次のチーズバーガーの画像を使うとよい。ハンバーガーのバンズが一つのリクエストを形成しているが、バンズの間には何百ものビーフパティがある!
悪意のあるユーザーがこのクエリの柔軟性を悪用した場合、リソースの過剰消費によってサーバーが窒息する可能性がある。
ページネーション機能の悪用
GraphQLには、ページ分割を処理する標準的な方法もいくつかあります。一般的なアプローチはオフセットベースのページネーションで、呼び出し元はフェッチするアイテムの数(リミット)と開始するアイテム(オフセット)を提供します。
例えば、商品検索から情報を返すクエリは次のようになる:
query { |
ページネーション・パラメーターを調整して、代わりにこのクエリーを実行したらどうだろう?
query { |
eコマースサイトでテストした同様の例で、私は受け取った反応を比較した:
$ du response*.json |
制限が8ではなく800に設定されているため、大きなファイルは小さなファイルの約100倍のサイズになると思うかもしれない。 検索結果は全体で800件ではなかった可能性が高い(おそらく16~20件のみ)。
ページネーションの悪用は、GraphQL クエリ パラメータを操作してサーバーに負荷を追加する方法のもう 1 つの例です。この機能を悪用することで、攻撃者は意図したよりもはるかに大きなリクエストをサーバーに処理させることができ、リソースの枯渇やサービス拒否(DoS)につながる可能性があります。
OWASP API4:2023 無制限のリソース消費
我々が実証してきたことは、OWASP API Security Top 10、特にAPI4:2023 Unrestricted Resource Consumptionに該当する。この脆弱性は、APIが特定の種類のインタラクションやリクエストを制限しない場合に発生し、サーバーをDoS攻撃やその他の運用妨害の危険にさらす。
APIが境界なく過剰なクエリやページ分割を許可すると、リソースの消費が急増する可能性がある。これはパフォーマンスの低下や、サーバーの完全な障害を引き起こす可能性さえある。適切な制限がなければ、これらの攻撃はサービスを中断させる可能性がある。高い運用コストが発生し、顧客が離れていき、ビジネスを失う可能性があります。
自分の身を守るには
これらのリスクに対処するには、APIリクエストを適切に規制する必要がある。リクエスト可能なデータ量を制限するコントロールを導入する。これには、クエリのサイズや数に制限を設けることや、レート制限やその他の保護手段を導入することが含まれる。
自分自身を守るための実践的な提案をいくつか紹介しよう:
- リクエストとレスポンスのペイロードサイズの制限:リクエストとレスポンスを返すデータのサイズに制限を設けることで、大きすぎるクエリがサーバーを圧迫するのを防ぐことができます。
- ページネーションの境界:ページネーションの最大制限を実装し、呼び出し元が妥当な数以上のレコードを取得しようとしないようにする。
- ウェブアプリケーションファイアウォール(WAF):WAFは悪意のあるアクティビティを検出してブロックし、GraphQL APIに対する潜在的な攻撃を阻止するのに役立ちます。LinodeMarketplace の Haltdos のような WAF を使用して、セキュリティのレイヤーを追加することを検討してください。
- APIセキュリティツール:悪意のある活動を検出し、軽減することができるツールは不可欠である。攻撃を示す可能性のある異常なパターンを特定するのに役立ち、システムに影響が及ぶ前に対策を講じることができる。
これらの手順を踏むことで、リソースの過剰消費によって GraphQL サーバーが悪用されるリスクを大幅に減らすことができます。APIインタラクションが適切に規制されていることを確認することは、サーバーの安定性とパフォーマンスの維持に役立ちます。
GraphQLを使ったビルドの詳細については、GraphQL Apolloをご覧ください:An Introduction with Examplesをご覧ください。
コメント