代表的な面接トピック

バックエンド面接:OAuth 2.0 Pushed Authorization Requests をどのように保護するか?

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

質問

きめ細かな権限と機密性の高いトランザクションコンテキストを持つ OAuth クライアントに対し、request_uri、リダイレクト URI、リプレイ、PKCE、エラー、ロールバックを保護しながら、どのように PAR を導入しますか?

プロンプトと適用されるコンテキスト

あなたは OAuth 2.0 認可サーバーのオーナーです。モバイルおよびエンタープライズ Web クライアントはきめ細かなスコープ、リソースインジケーター、決済コンテキストを保持していますが、チームはブラウザの URL に完全なリクエストを含めたくないと考えています。Pushed Authorization Request(PAR)エンドポイントを設計してください。クライアント認証、request_uri の生成とバインディング、有効期限、ワンタイム利用、リプレイ、リダイレクト URI 検証、PKCE、エラー、レート制限、ロールバックを網羅してください。

これはバックエンド、アイデンティティプラットフォーム、決済関連の面接に適したテーマです。RFC 9126 は、PAR をクライアントから認可サーバーへの直接プッシュとして定義しており、後のブラウザ認可リクエストで使用する request_uri を返します。優れた回答では、PAR を導入しても認可サーバーが後続のリクエストを検証する必要性がなくなるわけではないことにも言及します。

面接官が評価するポイント

  • クライアント、PAR エンドポイント、ブラウザ認可エンドポイント、トークンエンドポイントの境界を正しく設定できているか。
  • クライアント認証、ユーザー認証、リクエストの完全性、トークンバインディングを分離できているか。
  • request_uri の推測、すり替え(swapping)、リプレイ、期限切れ、リダイレクト URI 攻撃に対処できているか。
  • PKCE、state、nonce、JAR、PAR を適切なレイヤーに配置できているか。
  • TTL、冪等性、レート制限、監査、カナリアロールアウトを運用可能に設計できているか。

RFC 9700 は現在の OAuth 2.0 セキュリティベストプラクティスをまとめています。Amazon の SDE II 準備資料では、システム設計における信頼性、正確性、効率性、スケーラビリティ、セキュリティが強調されています。面接での評価シグナルは、これらの標準を実行可能なサービス境界に落とし込めるかどうかです。

明確化のための質問

  1. クライアントはコンフィデンシャルですか、パブリックですか?モバイルクライアントはクライアントシークレットを保護できますか、それとも PKCE とプラットフォームバインディングを使用する必要がありますか?
  2. リクエストにはどのような機密データが含まれていますか?署名または暗号化された JAR が必要ですか、また PAR の時点でどのフィールドを検証する必要がありますか?
  3. request_uri の有効期間、リフレッシュの許容、クライアントごとの同時実行数、およびグローバルレート制限の目標値はどのようなものですか?
  4. リダイレクト URI は固定で事前登録されていますか、それともエンタープライズテナントで動的登録が必要ですか?
  5. すべてのクライアントが PAR 経由で認可パラメーターを送信する必要がありますか?レガシークライアントはどのように移行しますか?
  6. ブラウザの更新、戻る操作、キャンセル、ネットワーク再試行で同じリクエストを再読み込みできるようにすべきですか?

30秒の回答フレームワーク

クライアントは PAR に HTTPS POST を送信して認証を行い、リダイレクト URI、スコープ、リソース、PKCE パラメーターを検証します。サーバーは高エントロピーで短命な、クライアントにバインドされた request_uri を生成し、JSON を返します。その後、ブラウザは認可エンドポイントに対して client_idrequest_uri のみを送信します。認可エンドポイントは、参照を消費する前にリクエスト、state/nonce、ユーザーの同意、PKCE を再度検証します。レート制限、監査、ワンタイム利用ポリシー、互換性フラグ、カナリアメトリクスによってロールアウトを制御します。

ステップバイステップの詳細な回答

1. 2ホッププロトコルを定義する

第1ホップは、クライアントから PAR への application/x-www-form-urlencoded ボディを持つ直接の HTTPS POST です。ここでクライアントを認証し、client_id、レスポンスタイプ、リダイレクト URI、スコープ、リソースインジケーター、state、nonce、PKCE を検証します。RFC 9126 は PAR に HTTPS を義務付けており、認可エンドポイントの拡張を許可しています。

第2ホップは、ユーザーエージェントから認可エンドポイントへのリクエストであり、通常は client_idrequest_uri のみを送信します。認可サーバーは、ブラウザから再送信された機密パラメーターを信用する代わりに、第1ホップで保存されたリクエストを取得します。これにより、クエリストリングの漏洩、URL サイズ制限、ユーザーエージェントによる改ざんのリスクを軽減します。

2. request_uri のストレージを設計する

request_uri は暗号学的に安全な乱数値で生成し、連番 ID や予測可能なビジネスキーは絶対に使用しません。完全なリクエスト、クライアント ID、作成時刻、有効期限、消費状態、ハッシュ化された監査フィールドを保存し、参照を作成したクライアントにバインドします。

TTL は短く保ち、expires_in として返します。期限切れの参照は invalid_request を返し、未知の参照はその存在履歴の有無を漏らすべきではありません。ワンタイム消費が最も安全です。製品仕様としてリフレッシュをサポートする必要がある場合は、読み取り回数制限、state/nonce バインディング、厳格な上限を設けた短いウィンドウを許可します。

3. クライアントとリクエストを検証する

mTLS や private_key_jwt など、トークンエンドポイントのルールを使用して PAR でクライアントを認証します。認証はどのクライアントがリクエストを送信したかを証明するものであり、ユーザーがサインインしたことやスコープに同意したことを証明するものではありません。登録されたリダイレクト URI、許可されたスコープ、リソース、レスポンスタイプを PAR で検証し、ユーザーコンテキストを必要とするチェックは認可時に再度実行します。

クライアントが署名付き Request Object を使用する場合は、JAR のルールに従ってその署名、発行者、対象者、有効期限、クリティカルフィールドを検証します。PAR は直接プッシュと参照ライフサイクルを扱い、JAR は Request Object の署名や暗号化を扱います。これらは組み合わせることができますが、互いを置き換えるものではありません。

4. PKCE、state、nonce を適切なレイヤーに配置する

PAR は引き続き code_challenge とそのメソッドを保持し、トークンエンドポイントはコード引き換え時に code_verifier を検証する必要があります。state はクライアントセッションをバインドして CSRF を緩和します。OIDC の nonce は認証リクエストを ID トークンにバインドします。request_uri が存在するからといって、これらの制御を削除したり、相互に交換可能として扱ったりする理由にはなりません。

5. すり替え、リプレイ、オープンリダイレクトを防止する

攻撃者がリクエストを取得済みの別のリクエストと置き換えた場合、スコープや保証レベルが変更される可能性があります。参照をクライアントにバインドし、認可リクエストのクライアントコンテキストが一致することを要求します。クライアントは一意の state と PKCE を使用し、OIDC は nonce を使用します。PAR がオープンリダイレクトのエントリポイントにならないよう、リダイレクト URI を厳格に一致させます。

消費済みの参照が再利用された場合は、列挙不可能な明示的エラーを返します。推測やリプレイを検出するために、クライアント、参照ハッシュ、時刻、リスクシグナル、結果をログに記録します。完全な認可リクエスト、クライアントアサーション、機密リソースパラメーターは、通常のアクセスログから除外します。

6. エラー、制限、可用性を設計する

無効なパラメーター、一致しないリダイレクト URI、不正な署名には、invalid_request などの OAuth エラーを使用します。不正なメソッドには 405、サイズ超過リクエストには 413、クォータ超過には 429 を返します。攻撃者が PAR のストレージを枯渇させないように、クライアント、テナント、IP、グローバルストレージごとに制限を適用します。

PAR が利用できない場合に、移行済みクライアントが通常の認可リクエストにフォールバックできるかどうかはセキュリティポリシーの判断です。決済や高リスクスコープの場合は、フローを暗黙的に弱めるのではなく、明示的に失敗させます。メタデータを介してレガシークライアントを移行し、段階的に require_pushed_authorization_requests を強制します。

7. データライフタイムの運用と可観測性

参照データは、TTL、消費、および必要な監査期間中のみ保持します。暗号化ストレージ、アクセス制御、最小化の原則を使用し、機密性の高い認可コンテキストを多数のキャッシュにコピーしないようにします。PAR の成功、検証失敗、期限切れ、重複消費、429 率、認可時の参照欠落率、トークン交換時の PKCE 失敗を追跡します。

通常のフローと PAR フローを並行してカナリア展開します。完了率、ファーストページのレイテンシ、モバイルフォールバック、セキュリティアラートを比較します。自動テストでは、同時消費、参照のすり替え、リダイレクト URI のバリエーション、ブラウザ更新、サイズ超過リクエスト、レガシークライアントの互換性を網羅する必要があります。

質の高い模範解答

私はこのフローを2つのホップに分割します。クライアントは HTTPS 経由で PAR を呼び出し、認証を行い、リダイレクト URI、スコープ、リソース、レスポンスタイプ、PKCE、state、nonce を検証します。サーバーは高エントロピーで短命な、クライアントにバインドされた request_uri を生成し、参照と expires_in のみを返します。その後、ブラウザはクライアント ID と参照を指定して認可エンドポイントを呼び出し、サーバーは元のリクエストを取得して認可、ユーザーセッション、state/nonce、PKCE のチェックを再度実行します。

参照にはリクエスト、クライアントバインディング、有効期限、消費状態が保存され、デフォルトでワンタイム利用となります。リフレッシュ機能は、短いウィンドウ、読み取り上限、監査を使用します。JAR は Request Object の署名や暗号化を処理し、PAR は直接プッシュと参照のライフタイムを処理します。厳格なリダイレクト URI マッチングによりすり替えやオープンリダイレクトを防止し、OAuth エラーやクライアント別、IP 別、テナント別の制限によって不正利用を可視化します。

旧フローを維持しながらクライアントメタデータごとにカナリア展開を行い、完了率、レイテンシ、期限切れ、重複利用、429、PKCE 失敗を測定します。高リスククライアントはサイレントフォールバックを行いません。ストレージ障害やリプレイの急増が発生した場合は、ロールアウトを停止して強制フラグを元に戻します。これにより、OAuth のユーザー同意およびコード引き換えの境界を変更することなく、URL 漏洩やパラメーター改ざんを削減します。

よくある間違い

  • クライアント認証、参照バインディング、有効期限を考慮せず、「パラメーターを POST に入れるだけ」と答える。
  • request_uri をアクセストークンとして扱ったり、推測可能なデータベース ID にしたりする。
  • PAR が自動的にリプレイを防止すると想定し、ワンタイム利用、TTL、state、nonce、PKCE を省略する。
  • それぞれの保護境界を説明せずに、PAR、JAR、PKCE を混同する。
  • リダイレクト URI の検証を PAR でしか行わず、認可時にブラウザのパラメーターを信用してしまう。
  • 413、429、同時消費、キャッシュ漏洩、機密ログの出力を無視する。
  • PAR 失敗時に無条件で通常の認可にフォールバックし、高リスクスコープの露出を広げてしまう。

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

request_uri の有効期間はどのくらいにすべきですか?

リスクに基づいて短い TTL を使用し、expires_in を返します。期限切れまたは消費後に削除または無効化し、監査用には最小限のハッシュ、クライアント、結果フィールドのみを保持します。

ブラウザの更新で参照を再利用できますか?

デフォルトはワンタイム利用とします。更新が必要な場合は、重複読み取りを監視しながら、短いウィンドウ、読み取り上限、state、nonce、クライアントセッションのバインディングを使用します。無制限の再利用は許可しません。

クライアント認証後も PKCE が必要なのはなぜですか?

クライアント認証は、リクエストを送信したクライアントを特定します。PKCE は、コード引き換えを検証ツール(verifier)を保持するリクエスタにバインドします。認可コードが傍受された場合、パブリッククライアントやモバイルクライアントにとって依然として重要です。

PAR は JAR を置き換えることができますか?

いいえ。PAR は直接プッシュ、ブラウザパラメーターの非表示、参照ライフタイムを扱います。JAR は Request Object の署名や暗号化を扱います。より強力な完全性や否認防止が必要な場合は、これらを組み合わせます。

レガシークライアントはどのように移行すべきですか?

認可サーバーのメタデータとクライアントポリシーによって PAR を有効にし、サポート状況を観察してから、選択したクライアントに対して require_pushed_authorization_requests を強制します。エコシステム全体を盲目的に切り替えるのではなく、制限された監査済みのレガシーパスを維持します。

PAR エンドポイントにリクエストが殺到した場合はどうしますか?

クライアント、テナント、IP、グローバルリソースごとに制限をかけ、ボディサイズとストレージ TTL に上限を設け、429 を返し、失敗率とストレージ基準値を監視します。トラフィックの負荷を理由に、高リスククライアントがサイレントにダウングレードしてはなりません。

公開情報ソース

関連する質問