• 診断項目 No.115/127
  • 公開ファイル・情報露出
  • 重大度 中(medium)

API仕様・GraphQL開発画面の公開とは?OpenAPI・Swagger UI・GraphiQLのリスクと診断基準

API仕様・GraphQL開発画面の公開とは、OpenAPI仕様書やSwagger UI、GraphiQLなどが本番で誰でも見られる状態です。リスク、Apollo Server・Spring Boot・FastAPIでの無効化、Webサーバーでの制限、診断基準を解説します。

結論(API仕様・GraphQL開発画面の公開)

API仕様・GraphQL開発画面の公開とは、APIの仕様書や開発用画面が、本番サイトで誰でも閲覧できる状態です。OpenAPI(旧称Swagger)の仕様書、Swagger UI、GraphiQL・GraphQL Playground・Apollo Sandboxなどの開発用画面が該当します。全エンドポイント・パラメーター・認証方式が一覧できるため、内部向けAPIであれば攻撃者に攻撃対象の地図を渡すことになります。意図した公開でなければ本番で無効化し、公開する場合も内部用の情報が混ざっていないか確認します。

この記事のポイント

  • OpenAPI仕様書には全エンドポイント、HTTPメソッド、パラメーター、認証方式が記載されます。
  • GraphQLのイントロスペクションが有効だと、すべての型・クエリ・ミューテーションを機械的に列挙できます。
  • オープンデータAPIなど公開目的の資料は問題ありませんが、内部用エンドポイントや検証環境のURLが混ざっていないか確認が必要です。
  • セキュリティAIチェッカーは4つのパスの内容署名を確認し、該当すれば△(意図の確認が必要)と判定します。×と対象外はありません。
  • /graphqlそのものを拒否するとアプリが動かなくなります。止めるのはIDE(GETのHTML応答)とイントロスペクションです。
診断項目名API仕様・GraphQL開発画面の公開
項目IDpublic.api-docs-surface
分類公開ファイル・情報露出
重大度・配点の重み中(medium) 重み 2
関連する標準・ガイドラインOWASP ASVS 5.0.0 V13.4.5(内部API等のドキュメントと監視エンドポイントを、意図しない限り公開しない、L2)、V4.3.2(GraphQLのイントロスペクションを、外部利用が前提でない限り本番で無効化する、L2)、V15.2.3(本番環境に開発用機能を含めない)、OWASP WSTG-APIT-01(API Reconnaissance)、WSTG-APIT-99(GraphQL)、CWE-200

API仕様・GraphQL開発画面の公開とは

API仕様・GraphQL開発画面の公開とは、OpenAPI(旧称 Swagger)の仕様書ファイル、Swagger UI、GraphQL の開発用IDE(GraphiQL、GraphQL Playground、Apollo Sandbox)が、本番サイトで誰でも閲覧できる状態です。

これらは、APIの全エンドポイント、パラメーター、データ型、認証方式を一覧できる資料です。外部の利用者に公開するAPIであれば意図して公開することもありますが、内部向けAPIの仕様や開発用画面が本番サイトに残っていると、攻撃者に攻撃対象の地図を渡すことになります。

セキュリティAIチェッカーのこの項目は、代表的な4つのパスに安全なGETを送り、仕様書や開発画面に特有の内容が返るかを確認します。公開が意図されたものかどうかは外部から判断できないため、該当しても「△ 要確認」とします。

API仕様書やGraphQL開発画面は何を明かしてしまうのか

OpenAPI / Swagger の仕様書

OpenAPI 3 系の仕様書はJSONの先頭付近に "openapi": "3.x.x"、Swagger 2.0 は "swagger": "2.0" を持ちます。paths 以下に全エンドポイントとHTTPメソッド、components.securitySchemes に認証方式が記載されます。

OWASP WSTG-APIT-01(API Reconnaissance)は、公開APIの詳細は通常 Swagger/OpenAPI 文書で公開され、その取得が攻撃対象の把握に重要であり、古い版の文書から廃止済みでも動作しているAPIが見つかることもあると説明しています。調査対象として /swagger、/swagger.json、/openapi.json などの典型パスを挙げています。

GraphQL のイントロスペクションと開発IDE

GraphQL は、スキーマ自体を問い合わせるイントロスペクション機能(__schema クエリ)を備えています。有効なままだと、すべての型・クエリ・ミューテーション(更新操作)が取得できます。GraphiQL はブラウザ上でクエリを試せるIDEで、イントロスペクション結果からドキュメントを自動生成します。OWASP WSTG-APIT-99 は、GraphiQL は主にデバッグ・開発用途であり、本番環境で利用者がアクセスできないようにするのがベストプラクティスだと述べています。

API仕様の公開についてよくある誤解

  • 「仕様書が見えても認証があるから安全」:認証・認可の実装漏れ(オブジェクト単位の認可不備など)を探す作業が大幅に容易になります。認可の不備はAPIで最も多い脆弱性の一つであり、仕様書はその探索を助けます。
  • 「GraphQL は単一エンドポイントだから隠れている」:イントロスペクションが有効なら、全機能を機械的に列挙できます。
  • 「公開APIだから仕様書を出すのは当然」:オープンデータAPIのように公開が目的のものは問題ありません。その場合も、内部用の管理系エンドポイントが同じ仕様書に混在していないか確認が必要です。

フロントエンドのソースコードの露出は「ソースマップの原文公開」、CMSの管理画面は「CMSセットアップ/管理入口の露出」で別に確認します。このページはAPI仕様書とGraphQL開発画面に絞って解説します。

API仕様・GraphQL開発画面の公開の診断基準(セキュリティAIチェッカー)

取得対象

次の4パスへ、リダイレクトを追わないGETを1回ずつ送ります(追加診断のリクエスト予算40件の範囲内。180KBを超える応答は先頭180KBだけを取得して判定)。

パス想定
/openapi.jsonOpenAPI 3 の仕様書
/swagger.jsonSwagger 2.0 の仕様書
/api-docsSwagger UI・仕様書の配置先として一般的なパス
/graphqlGraphQL エンドポイント(GETでIDEを返す実装がある)

内容署名

HTTP 200で、本文が次のいずれかに一致した場合を「該当」とします。

  • "openapi": "3(OpenAPI 3 系)
  • "swagger": "2(Swagger 2.0)
  • swagger-ui(Swagger UI のHTML・スクリプト)
  • <title>GraphiQL または <title>GraphQL Playground
  • apollo sandbox

ステータスコードだけでは判定しません。ソフト404(存在しないパスでも200でトップページ等を返す設定)では内容署名が一致しないため、誤検知になりません。

判定条件

判定条件得点係数
△ 要確認(warn)4パスのうち1件以上で内容署名が一致0.45
○ 問題なし(pass)いずれも一致しない(404・403・認証要求・別内容)1

この項目は「× 要改善」と「対象外(na)」を出しません。公開APIの資料として意図的に公開している場合があり、外部からは意図を判定できないためです。重み2のため、△ の場合は1.1点分の減点です。診断結果の根拠欄には、4パスのうち内容署名が一致した件数が表示されます。

判定の限界

  • 確認するのは4パスだけです。/v3/api-docs、/swagger-ui/index.html、/api/graphql など別パスに置かれた資料は検出しません。
  • /graphql へのGETでIDEを返さない実装(GETにはエラーJSONを返すなど)では、イントロスペクションが有効でも検出しません。本診断は状態変更の可能性を避けるため、イントロスペクションクエリは送りません。
  • 180KBを超える大きな仕様書は先頭180KBだけで判定します。"openapi"・"swagger" のキーは通常先頭付近にあるため検出できますが、署名が180KBより後ろにしかない場合は未検出になります。
  • 署名はJSON形式(キーが引用符で囲まれた "openapi": "3…")を前提にしています。YAML形式(openapi: 3.0.3)の仕様書だけを返す場合は一致しません。
  • Apollo Server は、既定の開発用ランディングページ(Apollo Sandbox を埋め込むHTML)を、Accept で text/html を優先するGETにだけ返します。本診断のGETは text/html を先頭に送るため、開発設定のまま公開されていれば検出されます。

自治体サイトでの判定例

状況判定
一般的なCMS構成で上記パスがすべて404○
オープンデータカタログ(CKAN等)や公開APIの説明として Swagger UI を /api-docs に置いている△
施設予約システムを同一ドメインに配置し、開発時の GraphQL Playground が /graphql に残っている△

オープンデータのように公開目的であれば、資料に内部用エンドポイントや検証用サーバーのURLが含まれていないことを確認し、診断結果に「意図した公開」と記録します。施設予約システムの例は、本番では無効化が必要です。

API仕様やGraphQL開発画面が公開されているとどんなリスクがあるか

  • 攻撃対象の網羅的な把握:仕様書から管理系API、一括取得API、ファイルアップロードAPIなど、画面からはたどれない機能が判明します。
  • 認可不備の悪用:仕様書のIDパラメーターを書き換えて他人のデータを取得する、管理者用の操作を一般利用者として呼び出すといった攻撃の試行が容易になります。
  • GraphQL 特有の攻撃:イントロスペクションで得たスキーマをもとに、深くネストしたクエリやエイリアスの大量指定による負荷攻撃、ミューテーションの不正呼び出しが行われます。
  • 検証環境の露出:仕様書の servers に開発・検証環境のURLが記載され、保護の弱い環境が攻撃されることがあります。

API仕様・GraphQL開発画面を非公開にする方法(Apollo Server・Spring Boot・FastAPI・Apache・nginx・IIS)

1. 本番で開発用UIとイントロスペクションを無効化する

Apollo Server(Node.js):

import { ApolloServer } from "@apollo/server";
import { ApolloServerPluginLandingPageDisabled } from "@apollo/server/plugin/disabled";

const server = new ApolloServer({
  typeDefs,
  resolvers,
  introspection: process.env.NODE_ENV !== "production",
  plugins: process.env.NODE_ENV === "production" ? [ApolloServerPluginLandingPageDisabled()] : [],
});

Spring Boot(springdoc-openapi、application.properties):

springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false

FastAPI(Python):

app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)

2. Webサーバーで到達を制限する

Apache(.htaccess):

<FilesMatch "^(openapi|swagger)\.json$">
  Require ip 203.0.113.0/24
</FilesMatch>
RedirectMatch 404 ^/api-docs(/|$)

nginx:

location ~ ^/(openapi|swagger)\.json$ { allow 203.0.113.0/24; deny all; }
location ^~ /api-docs { return 404; }

IIS(web.config、URL書き換えモジュールが必要):

<rewrite>
  <rules>
    <rule name="BlockApiDocs" stopProcessing="true">
      <match url="^(api-docs.*|openapi\.json|swagger\.json)$" />
      <action type="CustomResponse" statusCode="404" />
    </rule>
  </rules>
</rewrite>

Next.js(Vercel)では、仕様書を public/ に置かない、またはAPIルート側で process.env.NODE_ENV や認証を確認して404を返すようにします。

3. 公開が必要な場合の確認事項

  • 公開用の仕様書は、外部利用者向けのエンドポイントだけを含む別ファイルとして生成する。
  • servers に本番URLだけを記載し、検証環境・内部ホスト名を含めない。
  • example 値に実在の個人情報やAPIキーを入れない。
  • 各エンドポイントで認証・認可・レート制限がサーバー側に実装されていることを確認する。

4. API仕様公開の確認方法

for p in openapi.json swagger.json api-docs graphql; do
  printf "%s " "$p"
  curl -s -o /dev/null -w "%{http_code}\n" "https://www.example.lg.jp/$p"
done
curl -s https://www.example.lg.jp/openapi.json | head -c 200

外部から404・403になる、または公開用資料だけが返ることを確認します。GraphQL を使っている場合は、外部から次のようなイントロスペクションを試し、エラーになることも確認します(自組織のシステムに限って実施してください)。

curl -s -X POST https://www.example.lg.jp/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { name } } }"}'

サイトを壊さないための注意点(ガードレール)

  • 仕様書や開発画面の無効化は、外部連携先(他システム・委託先)がその資料を参照していないかを確認してから行います。
  • /graphql 自体を拒否するとアプリが動かなくなります。拒否するのはIDE(GETのHTML応答)とイントロスペクションであり、エンドポイントへのPOSTは残します。

よくある質問(FAQ)

Swagger UIを本番で公開してもよいですか?

外部の利用者に公開するAPIの資料であれば、意図して公開することもあります。その場合も、内部用の管理系エンドポイントが同じ仕様書に混在していないか、serversに検証環境のURLがないかを確認してください。内部向けAPIの仕様であれば本番では非公開にします。

API仕様書が見えても、認証があれば安全ではありませんか?

認証・認可の実装漏れ(オブジェクト単位の認可不備など)を探す作業が大幅に容易になります。認可の不備はAPIで最も多い脆弱性の一つであり、仕様書はその探索を助けます。

GraphQLのイントロスペクションとは何ですか?

スキーマ自体を問い合わせる機能(__schemaクエリ)です。有効なままだと、すべての型・クエリ・ミューテーション(更新操作)が取得できます。OWASP ASVS 5.0.0 V4.3.2は、外部利用が前提でない限り本番で無効化することを求めています。

GraphiQLやGraphQL Playgroundは本番に残してよいですか?

OWASP WSTG-APIT-99は、GraphiQLは主にデバッグ・開発用途であり、本番環境で利用者がアクセスできないようにするのがベストプラクティスだとしています。本番では無効化してください。

API仕様・GraphQL開発画面の公開が診断で△になったら、必ず直す必要がありますか?

公開が意図されたものかどうかは外部から判断できないため△としています。意図した公開であれば、資料に内部用エンドポイントや機密情報がないことを確認し、診断結果に「意図した公開」と記録します。意図しない公開なら無効化します。

/v3/api-docsなど別のパスにある仕様書も検出されますか?

検出しません。確認するのは/openapi.json、/swagger.json、/api-docs、/graphqlの4パスだけです。別パスやYAML形式の仕様書は手動で確認してください。

セキュリティAIチェッカーを利用する

この項目を含む127項目を、URLを入れるだけで無料診断します。

参考資料