MCPサーバーのセキュリティ: OAuth、オーディエンス・バインディング、混乱した代理
- リモート(HTTP)MCPサーバーが単なるAPIキーのエンドポイントではなく、OAuth 2.1のリソースサーバーである理由を理解する
- ディスカバリのハンドシェイクをたどる: 401 → 保護されたリソースのメタデータ → 認可サーバーのメタデータ → トークン
- トークンのオーディエンス・バインディング(RFC 8707)と、それがあるサービスのトークンを別のサービスで機能させない理由を説明する
- 混乱した代理の罠と、それを塞ぐ唯一のルール、すなわちクライアントのトークンを上流APIへ決してパススルーしないことを挙げる
- MCPサーバーをインターネットに公開する前に、短いハードニング・チェックリストを適用する
MCPは目新しいものからエージェントがツールに到達する既定の手段へと変わりました。つまりMCPサーバーは今や本物のデータと本物のアクションの前に立っています。STDIOで起動するローカルサーバーはその環境を信頼します。環境変数から資格情報を読み取り、防御すべきネットワーク境界がありません。同じサーバーをリモート(HTTP)にした瞬間、URLに到達できる者は誰でもそれを呼び出そうとできます。これはそれを認可の問題へと反転させ、MCP仕様は独自のAPIキー方式ではなくOAuth 2.1でそれに答えます。
このページはリモートのケースについてです。サーバーがSTDIO専用であれば、仕様はOAuthフローに従わないことを明示しています。環境から資格情報を取得して先に進んでください。
3つの役割
OAuthは問題を3者に分割します。MCPはそれらにきれいに対応します:
重要な考え方の転換: MCPサーバーはログインそのものを決して扱いません。 それは他者が発行したトークンを検証するだけです。この分離こそが、あなたが書いたサーバーの前に既製のアイデンティティプロバイダーを置けるようにするものです。
ディスカバリのハンドシェイク
クライアントは、どこで認証するかをあらかじめ設定しておく必要があってはなりません。MCPはディスカバリを自動化し、401によって駆動します:
- 最初のリクエストは裸で送られます。サーバーはHTTP 401 Unauthorizedと、そのリソースメタデータURLを指すWWW-Authenticateヘッダーでそれを拒否します。
- サーバー上の/.well-known/oauth-protected-resourceをGETします。文書のauthorization_serversフィールドは、クライアントが使用できる認可サーバーを少なくとも1つ指名します。
- ASの/.well-known/oauth-authorization-serverをGETし、authorizeエンドポイントとtokenエンドポイント、およびサポートされている機能を知ります。
- クライアントがこのASのクライアントIDを持っていない場合、/registerをPOSTして人間を介さずに1つを取得できます。クライアントはあらゆるMCPサーバーを事前に知ることはできないため、これは極めて重要です。
- クライアントはPKCEのverifier/challengeを生成し、resourceパラメータを含むauthorize URLへブラウザを開き、ユーザーが同意し、クライアントは返されたコード(verifierとともに)をアクセストークンと交換します。
- これで各リクエストはAuthorization: Bearer <token>を伴います。サーバーはそれを検証し、応答します。
クライアント側にハードコードされた認証設定がないことに注目してください。401がすべてをブートストラップします。それこそが要点です。エージェントは一度も見たことのないサーバーに接続し、どう認証するかを見つけ出せるのです。
オーディエンス・バインディング: 荷重を支えるルール
オーディエンス・バインディングが防ぐために存在する障害モードがこれです。あるユーザーがcalendar.example.com向けに発行されたトークンを持っているとします。evil.example.comにある悪意ある(あるいは単にずさんな)MCPサーバーが、クライアントを騙してそのトークンを自分に送らせます。もしevilがそれを受け入れれば、それはユーザーとしてカレンダーAPIを呼び出せるようになります。あるサービスのトークンが別のサービスで機能してしまいました。OAuthのセキュリティ境界が今まさに崩壊したのです。
その対策が**リソースインジケーター(RFC 8707)**です:
- 認可リクエストとトークンリクエストの両方で、クライアントは呼び出そうとしているMCPサーバーの正規URIに設定したresourceパラメータを含めなければなりません(MUST)。例: resource=https://mcp.example.com。ASがそれをサポートしているか不確かでも、これを送ります。
- サポートされている場合、ASはトークンにスタンプを押し、その特定のリソースサーバーに対してのみ有効にします。
- いかなる作業を行う前にも、MCPサーバーはトークンがそれ自身向けに発行されたことを検証しなければなりません(MUST)。オーディエンスクレーム(RFC 9068)をチェックします。他の誰か向けに鋳造されたトークンは、問答無用で401を受け取ります。
認可リクエスト上のresourceパラメータ(URLエンコード)
&resource=https%3A%2F%2Fmcp.example.com
正規URIは厳格です。https://mcp.example.comとhttps://mcp.example.com:8443/mcpは有効です。mcp.example.com(スキームなし)とhttps://mcp.example.com#frag(フラグメント)は無効です。相互運用性のため、末尾スラッシュのない形式を優先してください。
混乱した代理: トークンを決してパススルーしない
これは、善意のMCPサーバーを攻撃者のプロキシに変えてしまう間違いです。これはエージェントセキュリティにおける同じ混乱した代理の問題を、1つの具体的なルールに研ぎ澄ましたものです。
MCPサーバーはしばしば上流API(GitHub、データベースサービス、別のSaaS)を呼び出す必要があります。誘惑は、クライアントが渡してきたトークンを取り、それを上流へ転送することです。やめてください。 仕様は率直です。MCPサーバーはクライアントから受け取ったトークンをパススルーしてはなりません(MUST NOT)。
なぜ危険か: クライアントのトークンはあなたのサーバーをオーディエンスとして発行されました。もしあなたがそれを転送すれば、上流APIはそれをあなたから来たかのように信頼したり、あなたがすでに検証したと想定したりするかもしれません。そして今や1ホップ用にスコープされたトークンが、誰の同意モデルの外でも、2ホップ先で作業をしているのです。
- あなたのMCPサーバーが上流APIを呼び出す場合、それはそのAPIに対する別個のOAuthクライアントとして振る舞い、上流の認可サーバーから自分自身のトークンを取得します。2つの独立したトークン、2つの独立したオーディエンス。クライアントのトークンはあなたの玄関で止まります。
事前のハードニング・チェックリスト
リモートMCPサーバーが公共のインターネットに触れる前に:
- すべてのASエンドポイントはHTTPSでなければなりません(MUST)。リダイレクトURIはHTTPSまたはlocalhostでなければなりません(MUST)。それ以外は不可です。
- このサーバー専用に発行されていないトークンをすべて拒否します。これがサービス間のトークン再利用を止める唯一のチェックです。
- クライアントはPKCEを使用しなければならず(MUST)、傍受された認可コードは対応するverifierなしでは役に立たなくなります。
- ASは事前登録された値に対してリダイレクトURIを厳密に一致させなければならず(MUST)、クライアントはstateパラメータを使用し検証すべきです(SHOULD)。両者はオープンリダイレクトのフィッシングを防ぎます。
- 漏洩の被害を限定するため短命なアクセストークンを発行します。パブリッククライアントについてはリフレッシュトークンをローテーションします。トークンを安全に保管し、決してログに出さないでください。
- トークンはAuthorizationヘッダーに入れ、クエリ文字列には決して入れません。クエリ文字列に入れるとログやリファラに残ってしまいます。
- オーディエンス・バインディングはトランスポートのゲートです。それでも/docs/security/securing-agentsの最小権限、サンドボックス化、ヒューマン・イン・ザ・ループを適用してください。認証は誰かを語るだけで、リクエストが安全だとは語りません。
理解度チェック
理解度チェック
0/4出典とさらなる読み物
- MCP認可仕様(2025-06-18) — このページが要約する規範的なフロー、役割、MUST/SHOULD要件。
- MCPセキュリティのベストプラクティス — トークンのパススルー、混乱した代理、そしてそれらが禁止されている理由。
- RFC 8707 — OAuth 2.0のリソースインジケーター —
resourceパラメータとオーディエンス・バインディング。 - RFC 9728 — OAuth 2.0 保護されたリソースのメタデータ — リソースサーバーが自身の認可サーバーをどう広告するか。
- RFC 8414 — OAuth 2.0 認可サーバーのメタデータ および RFC 7591 — 動的クライアント登録。
- OAuth 2.1ドラフト — PKCE、通信のセキュリティ、トークン処理の要件。
- AILmanacの関連ページ: エージェントとツールのセキュリティ · プロンプトインジェクション · Claude CodeにおけるMCP。