【API・GraphQL編】エンドポイント列挙とBOLAの世界|CTF思考フレームワーク #09
こんにちは、アンペンです!
前回は、ログイン中の通信を支える「セッションIDという身分証」を、どう守るかを学びました。
今回は、画面の裏で動いているデータ通信、APIとGraphQLを見ていきます。画面がないからこそ攻撃者は直接エンドポイントを叩いてきます。エンドポイント列挙とBOLAの世界を見ていきましょう。

APIってアプリの裏側で動いてる仕組みでしょ?画面がないなら、攻撃しにくいんじゃないの?

逆だよ。画面というガードがない分、攻撃者はサーバーの「通用口」を直接叩ける。だから認可チェックの抜けがそのまま被害になるんだ。
ここまでは、私たちが目で見て操作する“画面”の話が中心でした。でも今回の主役は、ふだん誰の目にも触れない場所——アプリやサイトの裏側を流れる『API』です。スマホアプリでボタンを押した瞬間、裏では大量のデータ通信がやりとりされています。その見えない通信が、実は攻撃者にとって格好の的になる。今日はその理由を、お店の“通用口”にたとえながら見ていきましょう。
APIは画面というガードがないため、エンドポイント列挙・BOLA(認可抜け)・過剰なデータ返却・GraphQLの大量問い合わせなどに直接さらされます。守るときは「サーバー側の認可」と「返す情報を最小化する設計」が中心になります。
この記事で分かること
- API・GraphQLが「画面のないドア」になっている仕組み
- BOLA・エンドポイント列挙・GraphQL固有の問題
- 演習環境での観察方法と、守る側の基本対策
📖 はじめてのWebセキュリティ #09|API・GraphQL編
画面の裏側を流れる通信を題材に、APIならではの攻撃面と守り方を学びます。 シリーズ一覧を見る →
⚠️ 大事なお約束
この記事の確認は、CTF・公式ラボ・自分で作った検証環境だけで行ってください。実在するサービスのAPIに対し、列挙・認可迂回を試す行為は不正アクセス等に該当する可能性があります。
APIは「画面のないドア」
多くのWebサービスやスマホアプリは、内部でAPIを経由してデータを送受信しています。利用者には画面しか見えませんが、その裏では GET /api/users/123 のような形でサーバーと会話をしています。
攻撃者にとっては、画面を経由せず直接APIエンドポイントを叩ける状況が魅力的です。画面のボタンや入力チェックは関係なく、サーバー側の認可と検証が全てになります。
ここを誤解している人がとても多いんです。『入力欄で記号を弾いている』『管理者ボタンは非表示にしている』——そういう画面側の工夫は、APIを直接叩く攻撃者にはまったく効きません。なぜなら攻撃者は、画面というショーケースを素通りして、裏の窓口に直接話しかけるから。つまり画面のチェックは“利用者への親切”ではあっても、“守り”にはならない。本物の関所は、必ずサーバー側に置く必要があります。
そもそもAPIって何?という人向けに、ざっくり言うと『プログラム同士がデータをやりとりする窓口』です。たとえば GET /api/users/123 というのは、「123番のユーザー情報をください」というお願い。私たちが画面で“プロフィールを開く”ボタンを押すと、裏ではこういうお願いがこっそり飛んでいるわけです。そして攻撃者は、このお願いを画面を通さずに自分で組み立てて送れる——ここがいちばんのポイントです。
図解:画面経由とAPI直接の違い

同じデータ取得でも、画面を通る経路と、攻撃者がAPIを直接叩く経路では、サーバーが見ている情報は異なります。

お店には正面入口とは別に、業者向けの通用口や倉庫の搬入口があります。普段は使われない通用口でも、鍵が壊れていれば誰でも入れます。APIは、画面というショーケースの裏にある通用口です。鍵(=認可)が機能していなければ、画面のチェックがどれだけ厳密でも意味がありません。
ここで覚える用語:BOLA(ボーラ)
Broken Object Level Authorizationの略で、APIに渡された「対象オブジェクトのID」を書き換えるだけで、本来アクセスできないはずのデータを取得・更新できてしまう問題です。Webの世界のIDORと同じ概念で、OWASP API Security Top 10 の1位に挙げられている代表的なAPI脆弱性です。
BOLAという言葉、なんだか難しそうですが、正体は#07で出てきたIDORのAPI版です。やることは同じで、お願いの中の番号(/api/users/123 の 123)を、隣の人の番号にこっそり書き換えるだけ。サーバーが「いまこの通信をしているのは、本当に123番の人?」を確かめていなければ、他人の情報がするっと返ってきてしまう。Web画面でもAPIでも、“番号を信じすぎる”と同じ事故が起きるんですね。
APIから狙われる代表的な3つの問題
APIで狙われる代表的な問題は、大きく3つです。『番号を書き換えて他人のデータを取る(BOLA)』『隠れている窓口を探し当てる(エンドポイント列挙)』『一度に大量・深いデータを引き出す(GraphQL固有)』。どれも“画面という壁がない”ことから生まれる、API特有の悩みです。
代表的なAPI攻撃面

- BOLA(IDORのAPI版):対象オブジェクトIDを書き換えて、他人のデータを取得・更新する
- エンドポイント列挙:Swagger/OpenAPIドキュメント露出や規則的なURL命名から、内部APIが推測される
- GraphQL固有の問題:1つのクエリで深い・大量のデータを引き出されたり、イントロスペクションで内部構造が露出する
さらに、API応答が必要以上に多くの項目を返している(Excessive Data Exposure)と、画面では表示していない機密データが攻撃者の手元に届いてしまいます。
この『余分なデータを返してしまう』問題、地味ですがとても多いんです。たとえば画面には名前しか出していなくても、APIの応答(JSON)にはこっそり住所や電話番号、内部用のフラグまで含まれている——というケース。画面は氷山の一角で、APIはその下の本体ごと返してしまっている、というイメージです。攻撃者は画面を見ずに、この“本体”を直接のぞきにきます。だから「画面に出していないから大丈夫」は、まったく通用しないんです。
では、自分のブラウザでAPIの“素顔”をのぞいてみましょう。開発者ツールのネットワークタブを開けば、画面の裏で飛んでいる通信がそのまま見られます。あくまで自分のアカウント・自分の演習環境の範囲で、です。他人のIDを試したり本物のサービスに送ったりは絶対になし。「画面より多くの情報が返っていないか」を眺めるだけで、たくさんの発見があるはずです。
CTFでやってみよう:APIリクエストと応答を観察する
自分の検証環境で、APIの応答に含まれる情報を観察しよう
目的は他人のデータを取ることではなく、「APIが返している情報が画面より多すぎないか」に気づくことです。
- CTFや自分の検証環境で、ログイン後にプロフィール画面を開く
- ブラウザ開発者ツールのネットワークタブで、画面に対応するAPIリクエストを探す
- 応答JSONを開き、画面に表示されていない項目が含まれていないか確認する
- URLに含まれる対象ID(例:
/api/users/123の 123)が、自分のIDか他人のIDかを意識する - GraphQLの場合は、応答に含まれるフィールドと、クエリで指定したフィールドを比べる
GraphQLを使っている場合、もう一つ気をつけたい“しゃべりすぎ”があります。それが「イントロスペクション」です。

イントロスペクション?また難しい言葉が出てきた…

これはGraphQLの便利機能で、『このAPIにはどんなデータと項目があるか』を一覧で教えてくれるんだ。開発中はすごく助かるんだけど、本番でそのままにしておくと、攻撃者にとっては“店内の見取り図”を渡すようなもの。どこに何があるか丸わかりになる。だから本番では切っておくのが基本だよ。
守る側なら、認可と返却データの最小化を徹底しよう
APIを守る基本は、「サーバー側で全件の認可を確認する」「必要なデータだけを返す」の2点です。画面に見せていないからといって、APIから返さなくてよい理由にはなりません。
- APIごとに認可チェックを必ず通し、対象IDが「ログイン中ユーザーのもの」か検証する
- 応答に含めるフィールドは、画面の用途に必要なものだけに絞る(DTOやResponseクラスを定義)
- OpenAPI/Swagger定義は公開範囲を限定し、本番では未認証アクセスを許可しない
- GraphQLでは、クエリの深さ・幅・コストを制限し、本番ではintrospectionを無効化する
- 1分・1時間単位のレート制限で、列挙・大量取得を抑止する
- APIキー・トークンは権限を最小限に絞り、利用ログを監視する

『画面に見せていない=APIで返してもいい』じゃないんだね。

APIは画面とは別物として、独立して認可と返却フィールドを設計するのが安全だよ。
ここまでをひと言で言うと、APIは『画面とは別人格』として設計する必要がある、ということです。画面でいくら丁寧に隠しても、APIが無防備なら意味がありません。認可は窓口ごとに、返すデータは必要最小限に——この2つを“画面とは独立して”徹底するのが、APIセキュリティの背骨です。
まとめ:APIは「画面と独立した別の入口」
- APIは画面というガードを通らない直接の入口
- BOLA・エンドポイント列挙・GraphQL固有の問題が代表的なリスク
- 守りの基本はサーバー側の認可と返却データの最小化
- レート制限・ドキュメント公開範囲・GraphQL制限を組み合わせる
今日の持ち帰りは『画面の裏にも、同じ強さの鍵をかける』です。APIは便利で目立たないぶん、守りを忘れられがちな場所。でも攻撃者は、その目立たない通用口をこそ狙ってきます。番号を信じすぎない(認可)、しゃべりすぎない(返却の最小化)、開けっ放しにしない(レート制限・introspection無効化)。この3つを思い出せれば、見えない通信もしっかり守れます。
次回は、ブラウザのセキュリティを支える基礎ルール、CORSとSOP(同一オリジンポリシー)を見ていきます。境界線を突破される手口と守り方を学びましょう。
