QUICの0-RTTとEarly Data
再訪クライアントの初手にデータを載せて往復ゼロで応答を得る0-RTT。速さの裏にあるリプレイの穴と、QUICならではの防ぎ方まで踏み込みます。
- 1.0-RTTはTLS1.3のPSK再開を土台に、ClientHelloと同じ初送パケットにアプリデータ(Early Data)を暗号化して同梱する仕組み。
- 2.Early Dataは新鮮なECDHEを経ないためリプレイ耐性がなく、サーバーは冪等な要求以外を実行前提で処理してはならない。
- 3.QUICはトークンによるアドレス検証とEarly Dataの再送制限を組み合わせるが、完全なリプレイ排除には至らず1-RTTとのトレードオフが残る。
1-RTTとの違いはどこにあるか
/network/quic-internals/ で見た通り、QUICはTLS 1.3のハンドシェイクをトランスポートに統合し、初回接続でも1-RTTで確立できます。0-RTTはそこからさらに一歩進め、サーバーの応答を待たずに初送パケットへアプリデータを載せるモードです。往復数で言えば1-RTTが「1往復してから送る」のに対し、0-RTTは「送りながら往復する」形になります。
この差を生むのが、初回接続時にサーバーが発行した再開チケットの有無です。過去に接続したことのある相手にだけ0-RTTは使え、初回接続では原理的に成立しません。チケットとPSK再開の仕組み自体は/network/tls-session-resumption/で扱った内容と共通なので、ここではQUICのトランスポート層に固有の挙動に絞ります。
Early Dataが載る場所
QUICの0-RTTは、TLSのClientHelloに相当するCRYPTOフレームと、アプリデータを運ぶSTREAMフレームを同じ初送パケット群に詰めて送信します。鍵の系譜は次のようになります。
1. クライアントは前回保存した resumption PSK を取り出す
2. PSK から early_traffic_secret を導出(新規ECDHEは未実施)
3. early_traffic_secret でパケット保護鍵を作り、0-RTTパケットを暗号化
4. 同時に ClientHello(CRYPTO フレーム)も送出し、通常のハンドシェイクを並行開始
5. サーバーが受理すれば ServerHello 以降で 1-RTT 鍵に切り替わる
QUICでは0-RTTパケットと1-RTTパケットはヘッダ形式で区別されており、サーバーは受信したパケットがどちらの鍵で保護されているかをヘッダから即座に判別します。0-RTTで送ったSTREAMデータは、ハンドシェイク完了後に届く1-RTTパケットのデータと同じストリーム上でシームレスに継続します。
0-RTTで送れるのは前方秘匿性のないPSKのみを鍵材料とするデータです。TLS拡張のトランスポートパラメータも前回値をそのまま仮定して送信されるため、サーバーが前回と異なる設定(最大ストリーム数やフロー制御窓など)を要求している場合、クライアント側の想定とズレが生じます。
なぜリプレイに弱いのか
1-RTTのClientHello+ServerHelloの往復では、サーバーが返すServerHelloの中に新鮮な乱数とECDHEの鍵共有値が入り、それ以降の鍵はこの一回限りの値に依存します。攻撃者が過去のClientHelloを録画して再送しても、サーバーは毎回新しい乱数で応答するため、セッションごとに鍵が変わり同一処理は起こりません。
0-RTTのEarly Dataはこの仕組みの外側にあります。Early Dataの鍵は保存済みPSKだけから決まり、サーバー側の新規乱数を待たずに暗号化されるため、攻撃者が0-RTTパケットをネットワーク上でコピーして再注入すると、サーバーからは初回の送信と区別がつきません。サーバーがステートレスなチケット設計を採る限り、同じPSKが有効な期間中は「このEarly Dataを以前にも受け取ったか」を判定する手段がなく、再送を機械的に弾くことができません。
サーバーが「このリクエストは前にも処理したか」を判定する状態を持たない設計(ステートレスなセッションチケット)である限り、Early Dataのリプレイを暗号的に完全排除する手段はありません。だからこそ、0-RTTで受理してよい処理は冪等な読み取り(GETなど副作用のない要求)に限定するのが実務上の唯一の解になります。在庫減算・課金・トークン発行のような非冪等操作は、1-RTT確立後の保護された経路に回します。
QUICのアドレス検証とEarly Data制限
QUICはリプレイに加えて、UDPならではの送信元アドレス詐称による増幅攻撃にも対処する必要があります。ここで使われるのがアドレス検証トークンです。
- 初回接続でクライアントの到達性が未確認の間、サーバーは大きな応答を返す前に
Retryパケットでトークンを発行し、クライアントに再送させて送信元アドレスの実在を確認します。 - 再訪クライアントが0-RTTを試みる場合は、前回の接続時にNEW_TOKENフレームで受け取ったトークンを初送パケットに添えることで、この往復を省略できます。
- クライアントのアドレスがまだ未検証の間、サーバーが送信してよいデータ量はクライアントから受信済みの量の3倍までに制限されます(アンプ制限/amplification limit)。トークン検証に成功してアドレスが確認できれば、この倍率制限は解除されます。この仕組みが、詐称された宛先へ大量データを送りつける踏み台化を防ぎます。
| 観点 | 1-RTT | 0-RTT |
|---|---|---|
| 初送でアプリデータを送れるか | 不可(往復後) | 可能(PSK保持時のみ) |
| 鍵の新鮮さ | 新規ECDHEで毎回更新 | PSKのみ(ECDHE併用も選択可) |
| リプレイ耐性 | あり | なし |
| 許容できる処理 | 非冪等含め全般 | 冪等な読み取りに限定 |
| 前提条件 | なし(初回接続も可) | 再開チケットを保持済み |
1-RTTとのトレードオフをどう判断するか
0-RTTが効くのは「体感速度が特に重要で、なおかつリクエストが冪等」という条件を満たす場面、典型的には静的リソースの取得やアイドルなAPIのGET呼び出しです。逆に、フォーム送信や決済のように一度きりの処理を保証したい要求では、0-RTTの往復ゼロという利点よりもリプレイという欠点が上回ります。
サーバー実装の多くは、0-RTTで受理したデータをアプリケーション層に渡す際に「これはEarly Data経由である」というフラグを付与します。アプリケーション側はこのフラグを見て、非冪等な操作であれば処理を拒否するか、1-RTT確立後の再送を要求する設計にする必要があります。プロトコルスタックだけでは冪等性を判断できないため、この境界はアプリケーション層の責務として残ります。
「0-RTTがリプレイに弱い理由」は、Early Dataの鍵が新規ECDHEを経ずPSKのみに依存するため。「QUICのアンプ制限」は、アドレス検証前のサーバー送信量をクライアントからの受信量の3倍までに抑える仕組み。この2点は頻出。
まとめ
QUICの0-RTTは、TLS 1.3のPSK再開を土台に初送パケットへアプリデータを同梱することで往復ゼロを実現します。速さの代償はリプレイ耐性の喪失であり、これはプロトコルの欠陥ではなく設計上不可避のトレードオフです。安全に使うには、0-RTTで受理する処理を冪等なものに限定し、QUIC自身が持つアドレス検証トークンとアンプ制限を組み合わせて、詐称や増幅のリスクも同時に抑える必要があります。/network/http-versions/が示すHTTP/3の低遅延性は、この0-RTTと1-RTT統合ハンドシェイクの両輪で成り立っています。
ネットワーク Article
QUICの0-RTTとEarly Dataを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
QUIC
比較で見る軸
難易度: advanced / カテゴリ: ネットワーク / タグ数: 5
導入後に効く点
Early Dataは新鮮なECDHEを経ないためリプレイ耐性がなく、サーバーは冪等な要求以外を実行前提で処理してはならない。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- ネットワーク
- タグ数
- 5
判断チェックリスト
- 自社の用途が「QUIC / 0-RTT」に近いか確認する。
- 強みである「0-RTTはTLS1.3のPSK再開を土台に、ClientHelloと同じ初送パケットにアプリデータ(Early Data)を暗号化して同梱する仕組み。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。