代表的な面接トピック

一般面接:APIはどのような場合に 425 Too Early を返すべきか?

一般難しい
Offer.cc 編集チーム公開日 更新日

質問

ある API が TLS 1.3 経由で Early Data を受け入れています。どのリクエストが処理を継続でき、どのリクエストが 425 Too Early を受け取るべきでしょうか。また、クライアント、ゲートウェイ、およびサービスレプリカはリプレイによる副作用をどのように防ぐべきですか?

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

あるサービスが、再開された接続でのファーストバイトレイテンシを削減するために TLS 1.3 0-RTT を有効にしています。一部のリクエストはハンドシェイクが完了する前に到着し、アーリーデータは別の接続でリプレイされる可能性があります。API がいつ 425 Too Early を返すべきか、クライアントがどのようにリトライするか、そしてゲートウェイとすべてのサービスレプリカがどのように整合性を保つかを説明してください。

これはバックエンド、ネットワーク、インフラストラクチャ、およびセキュリティの面接に適しています。このテストはステータスコードを暗記しているかを問うものではありません。トランスポート層のリプレイリスクをリソースの実際の副作用に対応づけ、425、遅延処理(deferral)、アーリーデータの無効化、冪等性キー、および監査証跡の境界を定義できるかを評価します。

面接官がテストしていること

優れた回答では、425 はリプレイされる可能性のあるアーリーデータリクエストの処理をサーバーが回避するための安全性に基づく拒否であることを明確にします。これは一般的な過負荷、認証、またはビジネスバリデーションのエラーではありません。回答では、安全なメソッドと副作用を伴うリソースを区別し、リソースがアーリーデータを許容できるかをオリジンのみが把握できる理由を説明し、Early-Data ヘッダー、クライアントのリトライ、ゲートウェイの転送、およびレプリカの整合性を網羅します。また、リトライストーム、共有状態、不可逆な副作用にも言及します。

最初に明確にすべき質問

  • リクエストは実際にアーリーデータで到着したか、それとも信頼できる Early-Data: 1 を保持しているか?
  • その操作は状態の変更、課金、注文の発送、メッセージの送信、または外部への副作用のトリガーを伴うか?
  • クライアントはハンドシェイク完了後に、冪等性キーと重複排除ストアを使用して安全にリトライできるか?
  • ゲートウェイは 425 と Early-Data を理解しており、すべてのオリジンレプリカが単一のポリシーを共有しているか?
  • セッション再開、負荷、タイムアウト、リトライバジェットは安全性と可用性にどのように影響するか?

30秒での回答

「425 は、リプレイされる可能性のあるアーリーデータリクエストに対する安全性確保のための拒否であり、一般的なレート制限ではありません。オリジンはリソースのリスクに基づいて選択します。副作用がないリクエストや確実に冪等なリクエストはそのまま処理されるか遅延される一方、課金、書き込み、および不可逆なアクションはハンドシェイクの完了を待つべきであり、425 を受信することがあります。425 を受信したクライアントはハンドシェイク完了後にのみリトライします。ゲートウェイはシグナルを維持し、すべてのレプリカが同じポリシーを適用し、冪等性キーとサーバー側の重複排除によって繰り返しリクエストから保護します。」

ステップごとの回答

ステップ 1: アーリーデータとリプレイモデルを特定する

TLS 1.3 0-RTT により、クライアントはハンドシェイクが完了する前にアプリケーションデータを送信できます。完了したハンドシェイクは、その接続上のデータについてのみ伝えているにすぎません。別の接続が同じバイト列を受信しなかったことを証明するものではありません。したがって、サービスは接続の成功から一意性を推論することはできません。

ステップ 2: リソースの副作用を分類する

オリジンは、あるリソースに対するリプレイの影響を把握しています。読み取り、クエリ、および状態変更のない操作はリスクが低いことが多いですが、課金や監査パスに隠れた書き込みがないか検証してください。注文の作成、カード決済、クレジットの発行、権限の変更、メッセージの送信は二重に実行される可能性があるため、ハンドシェイクが完了するまで拒否するか遅延させます。

ステップ 3: 遅延、拒否、または 0-RTT の無効化を選択する

RFC 8470 では、TLS でアーリーデータを拒否するか、処理前にハンドシェイクを待機するか、またはクライアントが後でリトライできるように 425 を返すことが規定されています。いずれもリプレイリスクを軽減します。どれを選択するかは、リソースポリシー、メモリバジェット、クライアントの動作、および負荷によって決まります。ハンドシェイクの失敗すべての代用として 425 を使用しないでください。

ステップ 4: 425 を正しく送出する

リクエストがアーリーデータで到着したか Early-Data: 1 を保持しており、安全に処理できない場合、オリジンは 425 を返します。これはデフォルトではキャッシュ不可であり、そのペイロードは特定されたリソースの表現ではありません。クライアントがリトライできない場合やリクエストがアーリーデータではなかった場合は、回復が不可能になる可能性があるため、425 を送出してはなりません。

ステップ 5: クライアントのリトライ境界を定義する

アーリーデータを使用するクライアントは 425 の後にリトライすることが期待されますが、そのリトライでは再びアーリーデータを使用してはなりません。リクエストのセマンティクスを維持し、試行回数を制限し、バックオフを適用し、キャンセルや期限を遵守してください。リクエスト自体を安全にリトライできない場合は、無制限にリプレイするのではなく、呼び出し元に失敗を報告してください。

ステップ 6: ゲートウェイを介してシグナルを転送する

通常、ゲートウェイは特定のリソースがアーリーデータを受け入れるかどうかを判断できません。リプレイされた可能性のあるリクエストを転送する際、ゲートウェイは Early-Data: 1 を保持または追加する必要があり、シグナルを削除してはなりません。オリジンがこのメカニズムをサポートしていない場合は、ハンドシェイクを待つか拒否します。ゲートウェイがクライアントに代わってリトライできるのは、安全性が明示的に確認されている場合のみです。

ステップ 7: レプリカ間の整合性を維持する

すべてのオリジンレプリカ、エッジノード、および非同期ワーカーは、同一のアーリーデータポリシーを必要とします。あるレプリカが処理を遅延させ、別のレプリカが即座に課金を実行すると、攻撃者やパスの違いによって重複した副作用が生じる可能性があります。ポリシーのバージョン、冪等性キー、重複排除レコード、および観測可能なフィールドをレプリカ間で共有してください。

ステップ 8: リトライと過負荷の動作をテストする

完全なハンドシェイク、別のレプリカへのリプレイ、ハンドシェイク前に一部のみ到着するリクエスト、ゲートウェイの転送、クライアントのタイムアウト、およびサーバーの過負荷をテストします。アーリーデータの割合、425 の割合、リトライ、重複キー、重複した副作用、およびキューの増加を記録します。負荷がかかると、425 や 503 の応答が繰り返されることでリトライが増幅される可能性があるため、バジェットを設定し、0-RTT をグローバルに無効化できるようにしておきます。

トレードオフと境界

0-RTT は再開された接続でのファーストバイト待ち時間を短縮しますが、リプレイ分析、一貫したポリシー、および重複排除が必要です。メソッド名だけでは不十分です。名目上は安全なメソッドであっても、課金、監査、またはキャッシュの状態に書き込みを行う可能性があります。リソースレベルのポリシーのほうが信頼性が高くなります。

冪等性キーは重複した副作用を削減しますが、すべてのリクエストをアーリーデータに適したものにするわけではありません。重複排除の状態には、実用的な保持期間、レプリカ間での可視性、キーの衝突、リトライの期限切れ、およびストレージ障害に対する定義された動作が必要です。不可逆なアクションについては、複雑な補償トランザクションに依存するよりも、ハンドシェイクを待つほうが明確であることが多いです。

ロールアウト計画と証跡

各リソースに対してアーリーデータポリシー(許可、遅延、または 425)を登録します。書き込み操作に対しては冪等性キーと重複排除を追加し、ゲートウェイに Early-Data を伝播させ、オリジンで接続状態、ポリシーバージョン、およびリトライの相関を記録します。レプリカ間のリプレイ検証を実施し、注文、課金、メッセージが重複しないことを確認します。

リリース後は、リソースおよびクライアントバージョンごとに 425、リトライ、および副作用のメトリクスを監視します。クライアントがリトライルールに違反している場合は、オリジンの保護を弱めるのではなく、クライアントを修正するかエッジで 0-RTT を無効化します。RFC 8470 はゲートウェイとオリジンでの一貫した処理を要求しているため、リリースのチェックにはすべてのイングレスパスを含める必要があります。

よくある間違いとフォローアップ

425 をレート制限や過負荷として扱う

425 は、リプレイされた可能性のあるアーリーデータリクエストを対象としています。高い並行性、利用不可能な依存関係、クォータ超過は、異なるセマンティクスとバックオフ動作を持ちます。

すべての POST に対して 425 を返す

メソッドは単なる手がかりにすぎません。リソースのリプレイ耐性と、信頼性の高い冪等性および重複排除に基づいて判断してください。確実に冪等な書き込みは、遅延させるか、リソース固有のポリシーによって処理することができます。

再び 0-RTT を使用して 425 をリトライする

RFC 8470 では、425 の後のリトライでアーリーデータを避けることが求められています。そうしないと、クライアントはサーバーの保護を別のリプレイの機会に変えてしまいます。

ゲートウェイで Early-Data ヘッダーを削除する

シグナルを削除すると、オリジンはリクエストがアーリーデータを経由していないと判断してしまいます。ヘッダーを保持または追加し、オリジンが 425 をサポートしていることを確認し、確信が持てない場合はハンドシェイクを待ちます。

重複した課金が発生しなかったことをどのように証明するか?

レプリカ間で共有される冪等性キー、リクエストのフィンガープリント、および課金ステートマシンを使用してリプレイ演習を実行し、操作ごとに最終的なビジネス成果が1つだけであることを確認します。また、重複排除ストアの障害、タイムアウト後のクライアントリトライ、および重複したダウンストリームへの配信もテストします。HTTP ステータスコード単体では証明にはなりません。

公開情報ソース

関連する質問