課題とコンテキスト
決済APIでTLS 1.3のセッション再開(session resumption)を有効にしています。一部のリクエストがハンドシェイク完了前に到着し、ゲートウェイが425 Too Earlyを返します。どのリクエストが早期データ(early data)を使用できるか、リプレイによる副作用をどのように防ぐか、プロキシがそれをどのように伝達するか、そしてクライアントがいつリトライできるかを説明してください。
面接官が評価するポイント
- 0-RTTがレイテンシを短縮するものの、通常のハンドシェイクのようなリプレイ保護を提供しないことを理解しているか。
- 425、ネットワークタイムアウト、およびビジネス上の拒否を正確に区別し、
Early-Data: 1を使用できるか。 - 冪等性キー(idempotency key)、重複排除ウィンドウ、ゲートウェイポリシー、およびサーバーのステートマシンを結びつけて設計できるか。
- メトリクスと障害訓練によって、リトライによって二重請求が発生しないことを証明できるか。
明確化のための質問
- TLSを終端し、データが早期データであることを把握できるのは、どのクライアント、CDN、ゲートウェイ、またはオリジンですか?
- そのリクエストはGETや読み取りですか、それとも請求、発送、権限付与、メッセージ発行などの副作用を伴いますか?
- グローバルに一意な冪等性キーは存在しますか、保持期間はどれくらいですか、またリージョン間で共有されていますか?
- 425を生成するのは単一のゲートウェイですか、またすべてのSDKがそれを解釈してリクエストボディを再構築できますか?
- リトライのデッドライン、決済承認の有効期限、およびユーザーに見える状態はどのように整合していますか?
30秒での回答
0-RTTにより、TLS 1.3で再開するクライアントはアプリケーションデータを早期に送信できますが、攻撃者がそのデータをリプレイする可能性があります。サーバーは副作用を伴うリクエストに対して早期データを拒否すべきです。対応する中間ノードはEarly-Data: 1でそれを伝達でき、オリジンは425を返すことができます。フルハンドシェイクの後、クライアントはリプレイが安全な場合にのみリトライします。決済の書き込みについては、まず冪等性の結果を確認するかビジネス上の完了通知を待ちます。425は請求が失敗したことの証明ではありません。
詳細な回答
ステップ1: 0-RTTの境界を定義する
TLS 1.3の再開では、ラウンドトリップを削減するために早期データが許可されます。サーバーはこれを新規かつリプレイ不可能な証明として扱ってはなりません。攻撃者は許可されたウィンドウ内に同じバイト列をコピーして再送する可能性があります。
ステップ2: 副作用を分類する
公開GET、読み取り専用クエリ、または厳密に冪等なリクエストは、プロトコルおよびビジネス条件が許す場合に早期データを検討できます。請求、注文作成、権限付与、またはメッセージ発行は、サーバーに信頼できる冪等性とアトミックな重複排除がない限り、早期データを無効化すべきです。
ステップ3: Early-Dataと425を理解する
早期データをサポートする中間ノードは、転送時にEarly-Data: 1を追加できます。リプレイリスクの受け入れを拒否するオリジンは425を返します。これはリクエストの到着が早すぎたことを意味し、クライアントはハンドシェイク完了後に再送する必要があります。ヘッダーが存在しないことはリプレイリスクがゼロであることの証明ではないため、システム全体のデプロイを確認してください。
ステップ4: ゲートウェイポリシーを設計する
ゲートウェイは、メソッド、パス、および認証タイプごとに許可リストを維持します。決済、在庫、および権限変更のパスでは早期データを拒否し、読み取りパスでは接続状態を記録します。425を一般的な500に書き換えることなくそのまま維持する必要があります。
ステップ5: 冪等性と重複排除を設計する
クライアントはビジネスの意図ごとに予測不可能なキーを生成します。サーバーは副作用と重複排除結果をアトミックにコミットするか、同等のアトミックな境界を使用します。重複したキーは最初の結果を返し、二重請求を防止します。TTLは最大ネットワークリトライ、キューの遅延、および照合処理をカバーするように設定します。
ステップ6: 安全なリトライを規定する
425を受信した後は、完全な接続を確立し、デッドラインが有効でボディが再構築可能な場合にのみ再送します。GETは自動的にリトライできます。冪等性キーを持つ決済リクエストはまずその状態を読み取ります。リプレイ保護のない書き込みはビジネス上の確認処理に回します。意図あたりのリトライ回数に上限を設け、バックオフを使用します。
ステップ7: 検証とオブザーバビリティ
早期データ量、425の発生率、パス別のリトライ率、重複キー、成功した請求、および照合差分を記録します。プロキシやクライアントの障害を注入して、拒否、フルハンドシェイクでのリトライ、タイムアウト、重複配信、およびクロスリージョン重複排除をテストします。受け入れ条件として、ビジネス意図ごとに発生する副作用が最大で1回であることを証明しなければなりません。
模範回答
決済の書き込み処理は早期データの拒否リストに配置します。TLS終端が早期データを受信した場合、Early-Data: 1を転送し、オリジンはその書き込みに対して425を返し、診断用リクエストIDを保持します。フルハンドシェイク後、クライアントは盲目的にリプレイするのではなく、冪等性キーによって注文または請求を照会し、状態が不明でデッドラインが許す場合にのみ1回リトライします。サーバーはクロスリージョン境界を備えた状態で、キー、ビジネス結果、および重複排除レコードをアトミックに保存します。読み取り専用のGETは自動的にリトライできます。私は425、重複キー、照合差分を監視し、パスの障害訓練を実施して二重請求が発生しないことを証明します。
よくある間違い
- TLS 1.3 0-RTTが自動的にリプレイ安全であると思い込むこと。
- 425を無限にリトライしたり、500に書き換えたりすること。
- HTTPメソッドのみで安全性を判断すること(一部のGETにも副作用が存在します)。
- サーバー側でのアトミックな重複排除なしに、クライアント側だけで冪等性キーを保持すること。
- 状態を照会する代わりに、タイムアウトを「サーバーが何も処理しなかった証明」として扱うこと。
フォローアップの質問と回答
フォローアップ1: 425と503の違いは何ですか?
425は早期データにおけるリプレイリスクに対処し、フルハンドシェイク後の再評価を促します。503は一時的なサービス利用不可を意味し、そのリトライポリシーはキャパシティとRetry-Afterに依存します。
フォローアップ2: 誰がEarly-Dataを追加しますか?
この仕組みを理解している中間ノードが、オリジンに早期データを転送する際にEarly-Data: 1を追加します。TLS終端ポイントを確認し、プロキシがこのシグナルを破棄したり偽造したりしないようにしてください。
フォローアップ3: 0-RTT決済には冪等性キーだけで十分ですか?
いいえ。キーは予測不可能であり、結果とともにアトミックに永続化され、必要なリージョン間で重複排除され、十分な期間保持され、重複に対して同じ結果を返すことが証明されていなければなりません。
フォローアップ4: クライアントタイムアウト後に照会を行うのはなぜですか?
タイムアウトは、クライアントに応答が届かなかったことのみを証明します。冪等性の状態を照会することで、成功、処理中、未実行を区別し、二重請求を防ぐことができます。
フォローアップ5: カナリアリリースはどのように実施しますか?
読み取り専用パスと小規模なクライアントグループから開始します。パスごとに425とリトライの成功率を追跡し、重複した副作用、照合の異常、またはプロキシシグナルの欠落が発生した場合は早期データを自動的に無効化します。