代表的な面接トピック

バックエンド面接:複数の認可サーバーが存在する場合のOAuth Mix-Up攻撃をどのように防御するか?

バックエンド難しい
Offer.cc 編集チーム公開日 更新日

質問

あるクライアントが複数のOAuth認可サーバーと統合されています。Mix-Up攻撃を防ぐために、認可レスポンスにおけるイシュアー識別、コールバック検証、トークンエンドポイントの選択、および移行戦略を設計してください。

プロンプトとコンテキスト

あるSaaSクライアントが、エンタープライズIdP、パブリックIdP、およびパートナーの認可サーバーと統合されています。攻撃者は、サーバーAで開始されたリクエストをクライアントにサーバーBからのレスポンスとして処理させようとし、誤ったトークンエンドポイントにコードを送信させたり、誤ったクライアント設定を適用させたりする可能性があります。イシュアーのバインディング、認可レスポンス、トークン交換、メタデータ検出、エラー処理、移行をカバーするMix-Up防御を設計してください。

RFC 9207は、認可サーバーがOAuth認可レスポンス内で自身を識別できるようにissレスポンスパラメータを定義しています。RFC 9700は、Mix-Up防御策としてイシュアー識別を挙げています。ここでの目的は、stateのみに依存するのではなく、「ユーザーが戻ってきたこと」を「どの認可サーバーがこのフローを完了したか」にバインドすることです。

面接官が見ているポイント

  • 複数イシュアーのフローにおけるコード、トークンエンドポイント、およびクライアント設定の混同(Mix-Up)の認識。
  • イシュアーとstate、リダイレクトURI、PKCE、および認可リクエストレコードとのバインディング。
  • ディスカバリメタデータ、イシュアーURL、TLS、JWKS、およびトークンエンドポイント間の一貫性チェック。
  • 欠落、不明、競合、または偽造されたiss値の安全な処理。
  • 安全でないフォールバックを永久に残すことなく、古いIdPをサポートする移行計画。

前提条件の確認事項

  1. イシュアーのリストは静的ですか、動的に登録されますか、それともテナントごとに検出されますか?
  2. クライアントは1つの共有リダイレクトURIを使用しますか、それともイシュアーごとに個別のコールバックを使用しますか?
  3. OIDCはサポートされており、IDトークンのissaud、およびnonceの検証が必要ですか?
  4. レガシー認可サーバーはissを返しますか?また、それぞれが分離されたクライアント設定を使用できますか?
  5. PKCEは必須ですか?また、トークンエンドポイントは元のイシュアー設定を使用する必要がありますか?

30秒での回答

認可サーバーごとに、不変のイシュアー、ディスカバリドキュメント、認可エンドポイント、トークンエンドポイント、JWKS、クライアントID、およびリダイレクトURIポリシーを保持します。認可開始時にstate、nonce、PKCEを生成し、期待されるイシュアーを短命なサーバー側レコードに永続化します。コールバックでは、その期待される値と一致する許可されたissを要求し、記録されたイシュアー設定のみを使用してコードをトークンと引き換えます。欠落、不明、または競合する値がある場合はフローを停止します。クライアントが推測したり、暗黙的に切り替えたりすることは決してありません。

詳細な解説

1. イシュアーごとの信頼設定の確立

スキーム、ホスト、ポート、パスを含む正規のイシュアーURLを設定キーとして使用し、イシュアーの正確なルールに従って比較します。認可エンドポイント、トークンエンドポイント、JWKS、クライアント認証情報、許可されたスコープ、およびリダイレクトURIを保存します。

ディスカバリが許可されている場合は、ドキュメントのissuerが設定値と完全に一致することを要求し、HTTPS経由で取得します。ユーザーが指定したイシュアーによって任意のメタデータやJWKSが取得されるような事態は防がなければなりません。

2. 認可開始時におけるイシュアーのバインド

予測不可能なstateを生成し、state、期待されるイシュアー、クライアント設定バージョン、リダイレクトURI、PKCEチャレンジ、および作成日時をサーバー側のセッションまたは短命なストアに保存します。ブラウザは参照情報のみを保持し、変更可能なテナント設定は保持しません。

認可URLは、そのイシュアーおよびクライアント用に登録された正確なリダイレクトURIを使用する必要があります。テナントまたはIdPが動的に選択される場合は、サーバー側でそれを選択して記録します。コールバックが初期設定を遡及して選択してはなりません。

3. 認可レスポンスのissの検証

RFC 9207のissレスポンスパラメータは、承認されたイシュアーセット内に存在し、かつstateレコード内の期待されるイシュアーと一致している必要があります。issを持たないサーバーは、分離されたコールバック、分離されたクライアント、または信頼された境界を持つ互換パスでのみ使用できます。共有コールバックがすべてのイシュアーにわたって推測を行ってはなりません。

コードを処理する前に、state、イシュアー、エラーレスポンス、およびリダイレクトコンテキストを検証します。不明、重複、またはエンコーディングや大文字小文字のバリエーションは拒絶します。エラーページには一般的な失敗メッセージを表示し、未検証のURLを決してそのまま反映(リフレクト)させないでください。

4. トークン交換を元のイシュアーで維持

トークンエンドポイント、クライアント認証、およびPKCEベリファイアはstateレコードから読み取り、コールバック入力からURLを連結して構築することは絶対に避けます。トークンレスポンスにイシュアー、IDトークン、またはIDクレームが含まれている場合は、それらを元のイシュアーおよびクライアントIDと比較します。

PKCEはコードの引き換え者をバインドし、stateはブラウザセッションをバインドし、イシュアーは認可サーバーをバインドします。OIDCでは、IDトークンのイシュアー、オーディエンス、署名、有効期限、およびnonceの検証も必要です。コールバックのissだけでは不十分です。

5. ディスカバリ、JWKS、およびローテーションの保護

ディスカバリ、トークンエンドポイント、およびJWKSは、承認されたイシュアーの信頼境界内に留める必要があります。制御されたJWKSキャッシングとキーバージョンを使用します。kidが存在しない場合、制限された再取得を1回トリガーすることは許可されますが、任意のURLへのアクセスは決して行いません。イシュアー設定のバージョン管理を行い、処理中のstateが作成時に記録されたバージョンを引き続き使用できるようにします。

ディスカバリの失敗、イシュアーの不一致、TLSの失敗、または検証できない署名が発生した場合、リスクの高いフローでは安全側に倒して失敗(フェイルクローズ)させます。可用性を理由にトークンエンドポイントを別のイシュアーに切り替えてはなりません。

6. stateの悪用とリソース枯渇の防止

stateレコードには短いTTL、1回限りの消費、および同時実行制限を設定します。重複したコールバック、不明または期限切れのstate、および誤ったイシュアーはフローを無効化します。コールバックパラメータの上限を設定し、異常なJWT、URL、または長いエラー説明をログに記録しないようにします。

イシュアーの欠落や競合、不明なイシュアー、stateのリプレイ、ディスカバリの失敗、JWKSのリフレッシュ、PKCEの失敗、およびイシュアーごとの完了率を追跡します。設定ミスと攻撃を区別するために、アラートをテナントおよびイシュアーごとにグループ化します。

7. レガシー認可サーバーの移行

イシュアーとコールバックの機能をインベントリ化し、対応しているサーバーに対してRFC 9207を適用します。レガシーサーバーは、分離されたリダイレクトURI、分離されたクライアント、または明示的なバインディング、終了期日、監査を備えたサーバー側プロキシを使用できます。コードからイシュアーを推測する共有コールバックを無期限に維持してはなりません。

ロールアウト中は、完了率、エラー、コールバックのレイテンシ、およびイシュアーの競合を比較します。シグナルが悪化した場合は、新規テナントへのロールアウトを一時停止します。stateレコードとロールバックスイッチを保持しますが、PKCEを無効にしたり、バインドされていないトークンエンドポイントを再び開放したりしてはなりません。

模範回答

すべての認可サーバーに対して、固定されたイシュアー、ディスカバリドキュメント、認可エンドポイント、トークンエンドポイント、JWKS、クライアント、およびリダイレクトURIポリシーを管理します。認可開始時にstate、nonce、PKCEを生成し、期待されるイシュアーと設定バージョンをサーバー側に保存します。コールバックではstateとRFC 9207のissを検証し、期待されるイシュアーと等しい承認済みの値を要求します。その後のトークン交換では、記録されたエンドポイントとクライアント認証情報のみを使用します。

ディスカバリのイシュアー、OIDC IDトークンのイシュアー、オーディエンス、署名、およびnonceが再度チェックされます。イシュアーの欠落や競合、期限切れまたは再利用されたstate、JWKSの障害が発生した場合は、暗黙的に切り替えるのではなくフローを停止します。レガシーIdPには分離されたコールバックまたは期限付きのプロキシを使用します。イシュアーの競合、stateのリプレイ、PKCEの失敗、イシュアーごとの完了率を監視します。

よくある間違い

  • stateのみをチェックし、それが認可サーバーを識別していると思い込むこと。
  • コールバックのイシュアー入力から直接トークンやJWKSのURLを構築すること。
  • iss値が欠落または不明な場合に、すべてのIdPを試すことでフローを継続させてしまうこと。
  • ディスカバリイシュアー、IDトークンイシュアー、トークンエンドポイント間のクロスチェックを省略すること。
  • 移行中に共有コールバックとコードベースのイシュアー推測を無期限に残すこと。
  • PKCE、state、nonce、イシュアーバインディングを単一の統制策として説明すること。
  • 未検証のイシュアー、JWT、エラーURLをログやページに出力すること。

フォローアップ質問と回答

なぜstateだけではMix-Upを防げないのですか?

stateはブラウザセッションとコールバックをバインドしますが、レスポンスのイシュアーが分からなければ、クライアントは有効なstateを持つコードを誤ったトークンエンドポイントに送信してしまう可能性があります。イシュアーバインディングがそのサーバーのアイデンティティを提供します。

コールバックにissが含まれていない場合でもフローを継続できますか?

レガシーサーバーごとに個別のコールバックやプロキシを用意するなど、明示的に分離された互換性ポリシーの下でのみ可能です。共有コールバックがイシュアーを順番に試して推測してはなりません。

ユーザーがイシュアーURLを入力することは許可されますか?

選択内容は承認されたイシュアーにのみマッピングされる必要があります。任意の入力に対してサーバーがディスカバリやJWKSを取得してはならず、それを行うとSSRF、フィッシング、およびトラストルートのリスクが生じます。

テナント設定の取り違えをどのように防ぎますか?

stateレコードにはテナント、イシュアー、設定バージョン、リダイレクトURIが含まれます。コールバックとトークン交換はそのレコードのみを読み取ります。設定の更新があっても、TTL内の処理中stateが上書きされることはありません。

OIDCでは他に何が必要ですか?

コールバックのissに加えて、IDトークンの署名、イシュアー、オーディエンス、有効期限、発行時刻、nonce、および必要な認証コンテキストを検証します。コールバックパラメータでIDトークンの検証を代替することはできません。

移行によってセキュリティが弱まっていないことをどのように証明しますか?

イシュアーごとに適用されたポリシー、有効化時刻、コールバックタイプを記録します。欠落・偽造されたイシュアー、テナント間のstate、エンドポイントの置き換え、繰り返されるコールバックをテストし、フォールバックへのヒット数がゼロまたは承認された例外の範囲内に留まっていることを監視します。

公開情報ソース

関連する質問