
はじめに
こんにちは、VポイントマーケティングAIエンジニアの三浦です。 今年のゴールデンウィークに思い切ってスマートフォンを買い換えました。前の機種はもうだいぶ長いこと使っていたので、新しい機種になって「画面がスムーズに動く・・・!」など、いろいろスマートフォンの進化に感動しています。
さて、前回MCP Serverの認可について調べたことをまとめました。
前回の記事はどちらかというと概念に近い内容だったのですが、もう少し具体的な内容もまとめたいなと考えて、MCPのドキュメントの「Security Best Practices」というタイトルのページを最近読んでいました。
このドキュメントではMCPサーバーの認可の仕様において、実装をおざなりにするとどのようなリスクが発生しうるのかがまとめられています。今回はこの中からMCPサーバーで起こりうる「混乱した代理問題」と「トークンパススルー」という問題と、それを防ぐためにMCPサーバーにどのような実装が求められるのかについて調べてみたことをまとめてみたいと思います。
混乱した代理問題(Confused Deputy Problem)
混乱した代理問題は、権限を持たないクライアントがその権限を持つプログラム(代理人)にアクセスして指示を出すことで、本来できないはずの操作が可能になってしまうというコンピュータセキュリティにおける脆弱性の一種です。
この問題がMCPサーバー、特にサードパーティのAPIへの橋渡しをするMCPプロキシサーバーとして動作するときに発生する可能性があります。
具体的には以下の条件が揃ったときに混乱した代理問題が発生してしまいます。
- MCPサーバーがサードパーティAPIと静的なクライアントIDで接続している
- MCPサーバーがMCPクライアントに「動的クライアント登録」を許可している
- サードパーティAPIの認可サーバーがユーザーの同意をユーザーのブラウザに同意クッキーで保存し同意画面を省略できる
- MCPサーバーがサードパーティAPIに接続する前にリクエストを送ってきたクライアントの検証処理を実装していない
この時以下のフローで攻撃者は攻撃が可能になってしまいます。
- ユーザーが正規のクライアントでMCPサーバーを通じてサードパーティAPIを利用できる状態になっている
- ブラウザには認可サーバーの同意クッキーが存在している
- 攻撃者がユーザーに不正なMCPクライアントに対する動的クライアント登録のリクエストを発行するURLを送信する
- ユーザーがそのURLにアクセスすると、同意クッキーにより認可サーバーはそのユーザーが認可済みと判断
- MCPサーバーとサードパーティAPIでトークンの交換が行われる
- MCPサーバーは動的に登録された攻撃者の
redirect_urlにMCPサーバーの認可コードを送信する - MCPサーバーと攻撃者の間でトークンの交換が行われる
- 攻撃者はMCPサーバーを通じてサードパーティAPIを実行して対象者の情報にアクセスできてしまう
つまりMCPサーバーを通じて攻撃者が攻撃対象者の権限でサードパーティAPIにアクセスできるようになってしまいます。
これを防ぐためにはMCPサーバーでユーザーごとにどのクライアントIDでサードパーティAPIの使用を許可したのかを管理しなければいけません。もしまだそのユーザーが許可していないクライアントIDでサードパーティAPIへの認可が求められた場合はMCPサーバー側でそのユーザーに対して問題がないか同意を確認するUIを提供しないといけません。
同意を確認するUIを作る際には以下の対応を必ず守ります。
- リクエストを求めているMCPクライアント名を表示する
- MCPクライアントがサードパーティAPIのどの
scopeを必要としているか表示する - トークンや認可結果が送られる
redirect_urlを表示する - CSRF(Cross-Site Request Forgery)対策を
stateパラメータやCSRFトークンで実装する - frame-ancestors CSPやX-Frame-Options: DENYのオプションで攻撃者のサイト内に埋め込まれないようにする
最後の二つは攻撃者のサイトに同意確認UIが埋め込まれ、ユーザーが意図せずに同意ボタンをクリックしてしまうことを防ぐために重要です。
同意状態を保存するクッキー(Consent Cookie)にもセキュリティ対策が必要です。クッキーの内容が攻撃者に見られないこと、改ざんされないこと。さらにクッキーの内容に「同意済みフラグ」のみしか設定しないと不正なMCPクライアントでもユーザーの認可を得ずにサードパーティAPIにアクセスできてしまう恐れがあります。クッキーには必ず同意済みのMCPクライアント(クライアントID)も含めます。
リダイレクトURLのチェックも重要です。そのクライアントIDと紐づいたリダイレクトIDであることを確認し、再登録をせずに送られてきた異なるURLははじかなければなりません。検証ではパターン一致を使わずに完全一致することを確認します。
OAuthのCSRF対策に使用するstateパラメータにも厳密な扱いが求められます。OAuthのstateは同意からアクセストークンの取得までを同一人物(ブラウザセッション)で実行されたことを検証する仕組みです。
- MCPサーバーは
stateパラメータを暗号技術を用いて安全にランダム生成する - 生成した
stateはMCPサーバーが提供する同意UIでの同意後にMCPサーバーのセッション管理で安全に管理するか暗号化クッキーで保存する - 同時にサードパーティAPIの認可サーバーに
stateをリクエストに含めてリダイレクトする - ブラウザでユーザーが認証後にMCPサーバーの
callbackに戻ってくるstateの値と保存した値が一致していることを検証する stateが含まれていない、または保存したstateと一致しないcallbackリクエストはすべて弾かなければならないstateは一度使ったら削除し、10分などの短い有効期間を持たせる
トークンのパススルー
MCPサーバーは受け取ったアクセストークンを検証して信頼できる認可サーバーが発行した、自分自身に対して発行されたものかを必ず検証し、そうでないものは受け取ってはいけません。アクセストークンを検証せずにそのまま使用する、いわゆるトークンのパススルーによってそのMCPサーバーだけでなく、連携するサービスにも不利益を与えてしまう可能性があるからです。
たとえばあるMCPサーバーがプロキシサーバーとして別のAPIを呼ぶ仕様になっていた場合、MCPサーバーがクライアントから受け取るアクセストークンは別のAPIのアクセストークンではなく、そのMCPサーバー向けに発行されたものでなければなりません。もしMCPサーバーがそれを検証しないと、本来MCPサーバーにアクセスができないクライアントでも、MCPサーバーが呼び出すAPI側では有効なアクセストークンだった場合に制限なくMCPサーバーを利用できてしまいます。
また、アクセストークンを横流ししてMCPサーバーが別のAPIを呼び出すと、本来そのMCPサーバーが呼び出しているはずなのにAPI側ではMCPクライアントが呼び出しているように認識してしまう可能性があります。API運営側の記録に不整合が生じてしまうことが考えられます。さらにAPI側では呼び出し元のクライアントに応じた前提を持っていることもあります。もしアクセストークンをそれを取得したクライアントではなくMCPサーバーが使うようになってしまうとその前提が壊れてしまうかもしれません。
セキュリティ上の問題もあります。1つのアクセストークンでMCPサーバーと呼び出されるAPI両方にアクセスできてしまう状態は他に接続しているサービスへの不正なアクセスを攻撃者に許可してしまう恐れがあります。そういったセキュリティ上の問題を防ぐための制限が今後導入されることを踏まえ、今の段階からアクセストークンの検証は実装しておく必要があります。
まとめ
今回のドキュメントは読んでいて個人的にかなり難しい・・・と感じました。MCPサーバーが別のAPIのプロキシサーバーとしてふるまう場合、MCPサーバーはMCPクライアントにとってはサーバーで、呼び出すAPIにとってはクライアントとしてふるまっている、というところが自分にとって理解が難しい点なのだと思います。
自分は安全に利用できるMCPサーバーを構築したい、という目的で最近セキュリティ関連のドキュメントを読んでいたいのですが、一方で自分が普段エージェントとMCPサーバーを接続するときにこういったセキュリティの問題が起こりうるのか、ということを知ることができて勉強になりました。特にブラウザで表示される同意画面についてはユーザーが正しく内容を確認したうえで同意しないと意図しない場所でアクセストークンが使われてしまう可能性があります。この辺りをちゃんと意識して使うことが必要だと感じました。