QUIC-VN
RFC 9368 Compatible Version Negotiation for QUIC
https://www.rfc-editor.org/info/rfc9368
Updates: RFC 8999 QUIC-INVARIANTS
QUICの互換バージョンネゴシエーション
概要
QUICは完全なバージョンネゴシエーションメカニズムを提供しておらず、クライアントが選択したバージョンが受け入れられないことをサーバーが示す方法のみを提供しています。このドキュメントでは、クライアントとサーバーが相互にサポートされるバージョンを選択できるバージョンネゴシエーションメカニズムについて説明します。オプションとして、クライアントが選択したバージョンとネゴシエートされたバージョンが互換性のあるファーストフライトフォーマットを共有している場合、追加のラウンドトリップを発生することなくネゴシエーションを行うことができます。このドキュメントはRFC 8999を更新します。
1. はじめに
QUICのバージョン不変特性 QUIC-INVARIANTS はバージョンネゴシエーションパケットを定義していますが、エンドポイントがそれを受信した場合の対応方法は規定していません。QUICバージョン1 QUIC では、サーバーがバージョンネゴシエーションパケットを使用して、クライアントが選択したバージョンが受け入れられないことを示すことができますが、クライアントがその情報を安全に利用して、相互にサポートされているバージョンで新しい接続を確立することは許可されていません。本文書は、バージョンネゴシエーションパケットを活用したバージョンネゴシエーションメカニズムを定義することで、QUIC-INVARIANTS を更新します。
適切な安全メカニズムが整備されていれば、バージョンネゴシエーションパケットは、2つのQUIC実装が、完全に異なる2つのバージョンのQUIC間でネゴシエーションを行うメカニズムの一部となります。本文書では、必要に応じて接続確立に追加のラウンドトリップを追加する、バージョンネゴシエーションパケットを用いたバージョンネゴシエーションを規定します。
増分バージョンの多くは以前のバージョンと概ね類似していることを考えると、可能な限り追加のラウンドトリップを避けることは有益です。本仕様では、バージョン間の類似性を活用し、「互換性のある」バージョン間で追加のラウンドトリップなしでネゴシエーションできる、シンプルなバージョンネゴシエーションメカニズムも定義しています。
1.1. 表記規則
本文書におけるキーワード「MUST(しなければならない)」「MUST NOT(してはならない)」「REQUIRED(必須)」「SHALL(する)」「SHALL NOT(しないべき)」「SHOULD(すべき)」「SHOULD NOT(すべきではない)」「RECOMMENDED(推奨される)」「NOT RECOMMENDED(推奨されない)」「MAY(してもよい)」「OPTIONAL(任意)」は、ここで示すようにすべて大文字で表記されている場合に限り、BCP 14 RFC2119 RFC8174 の規定に従って解釈されます。
1.2. 定義
本文書では、以下の用語を使用します。
特定のQUIC接続において、「最初のフライト(first flight)」パケットとは、クライアントがサーバーからの応答を受け取る前に、接続を開始するために作成・送信するパケットセットを指します。
特定のQUIC接続において、「クライアントの選択バージョン(client's Chosen Version)」とは、接続の最初のフライトにおけるQUICバージョンを指します。
「オリジナルバージョン(Original Version)」とは、クライアントがサーバーに送信する最初のパケットのQUICバージョンです。バージョンネゴシエーションが複数の接続にまたがる場合(セクション2.4を参照)、オリジナルバージョンは最初のQUIC接続におけるクライアントの選択バージョンと等しくなります。
「ネゴシエーションバージョン(Negotiated Version)」とは、バージョンネゴシエーションプロセスが完了した後、接続で使用されるQUICバージョンです。
「最大セグメント有効期間(Maximum Segment Lifetime)」(MSL)とは、QUICパケットがネットワーク内に存在できる時間を表します。実装によってこれを設定可能にすることができ、推奨値は1分です。ここでの「セグメント」という用語は、TCPのセクション3.4.1に由来することに注意してください。
2. バージョンネゴシエーションのメカニズム
本文書では、バージョンネゴシエーションを実行する2つの方法を規定します。1) 「非互換(incompatible)」はラウンドトリップを必要とし、すべてのバージョンに適用されます。2) 「互換(compatible)」はラウンドトリップを省略できますが、バージョンに互換性がある場合にのみ適用されます(セクション2.2を参照)。
クライアントは、オリジナルバージョンを選択し、長いヘッダーを持つQUICパケットの最初のフライトをサーバーに送信することにより、QUIC接続を開始しますQUIC-INVARIANTS。クライアントの最初のフライトにはバージョン情報(セクション3を参照)が含まれます。これは、オプションで互換バージョンネゴシエーションを有効にする(セクション2.3を参照)ため、およびバージョンダウングレード攻撃を防ぐ(セクション4を参照)ために使用されます。
この最初のフライトを受信すると、サーバーは選択されたバージョン(この場合はオリジナルバージョン)から最初のフライトを解析する方法を知っているかどうかを確認します。解析できない場合は、非互換バージョンネゴシエーション(セクション2.1を参照)を開始し、クライアントは異なるバージョンで新しい接続を開始します。たとえば、クライアントがサーバーが解析できないバージョン A で接続を開始した場合、サーバーは非互換バージョンのネゴシエーションを開始します。その後、クライアントがバージョン B で新しい接続を開始すると、最初の接続のクライアント選択バージョンは A、2 番目の接続のクライアント選択バージョンは B、シーケンス全体のオリジナル バージョンは A になります。
サーバーが最初のフライトを解析できる場合、クライアントの選択バージョンを使用して接続を確立するか、セクション 2.3 で説明されているように、他の互換性のあるバージョンを選択することもできます (MAY)。
サーバーが特定のバージョンの最初のフライトを完全にサポートしていなくても解析できる可能性があることに注意してください。つまり、最初のフライト パケットを解析するのに十分なバージョンの仕様を実装しているが、そのバージョンを使用して接続を完全に確立するには不十分であるということです。
2.1. 非互換バージョンネゴシエーション
サーバーは、バージョンネゴシエーションパケットを送信することにより、非互換バージョンネゴシエーションを開始します。このパケットには、サーバーのオファーバージョンセット(セクション5参照)の各エントリがサポートバージョンフィールドに含まれるものとします(SHALL)。サーバーは、サポートバージョンフィールドに予約バージョン(QUICのセクション6.3で定義)を追加してもよいものとします(MAY)。
クライアントは、セクション4の規定に従い、バージョンネゴシエーションパケットにクライアントが試みたオリジナルバージョンが含まれている場合、そのパケットを無視します。また、クライアントは、QUIC-INVARIANTSのセクション6の規定に従い、誤った接続IDフィールドを含むバージョンネゴシエーションパケットも無視します。
バージョンネゴシエーションパケットを受信すると、クライアントはサーバーが提供するリストからサポートするバージョンを検索します(SHALL)。見つからない場合は、接続試行を中止します(SHALL)。見つかった場合は、相互にサポートされるバージョンを選択し、そのバージョンで新しい最初のフライトを送信します(SHALL)。このバージョンがネゴシエートバージョンとなります。
新しい最初のフライトでは、エンドポイントはネゴシエーションバージョンを使用して接続を確立できます。ネゴシエーションバージョンのハンドシェイクでは、バージョンネゴシエーションが正当であること、つまり攻撃者がバージョンネゴシエーションプロセスに影響を与えるためにパケットを挿入していないことを確認するために必要なバージョン情報(セクション3を参照)が交換されます(セクション4を参照)。
サーバーのみが非互換バージョンネゴシエーションを開始できます。クライアントはバージョンネゴシエーションパケットを送信してはならず(MUST NOT)、サーバーは受信したバージョンネゴシエーションパケットをすべて無視しなければなりません(MUST NOT)。
2.2. 互換性のあるバージョン
AとBがQUICの異なるバージョンである場合、バージョンAの最初のパケットフライトをバージョンBの最初のパケットフライトに変換できる場合、AはBと「互換性がある」と言われます。例えば、バージョンAとBのワイヤイメージとハンドシェイク中の動作が完全に同一であるが、ハンドシェイク後に異なる場合、AはBと互換性があり、BはAと互換性があります。最初のフライトの変換は損失を伴う可能性があることに注意してください。QUICバージョン1の0-RTTパケットなど、一部のデータは変換中に無視され、後で再送信される可能性があります。
バージョンの互換性は対称的ではありません。バージョンAはバージョンBと互換性があり、バージョンBはバージョンAと互換性がない場合があります。例えば、バージョンBがバージョンAの厳密なスーパーセットである場合、つまりバージョンAにストリームとSTREAMフレームの概念が含まれ、バージョンBにストリームの概念と、STREAMフレームおよびTUBEフレームに加えてチューブの概念が含まれている場合、バージョンAはバージョンBと互換性がありますが、バージョンBはバージョンAと互換性がありません。
バージョン互換性とは、最初のフライトのすべてのインスタンスが他のバージョンへの変換に成功することを意味するわけではないことに注意してください。バージョンAを使用した最初のフライトは、次の2つの条件が満たされている場合にバージョンBと「互換性がある」と言われます。(1) バージョンAがバージョンBと互換性があり、(2) この最初のフライトからバージョンBへの変換が明確に定義されている場合です。例えば、バージョンBが最初のフライトでバージョンAが解析できない、あるいは無視できない新しいフレームを導入したことを除き、すべての点でバージョンAと同等である場合、そのフレームが使用されていない接続では変換が成功するため、バージョンBはバージョンAと互換性がある可能性があります。この例では、この新しいフレームを伝送するバージョン B を使用した最初のフライトは、バージョン A と互換性がありません。
QUIC の新しいバージョンが定義されると、特に指定がない限り、他のバージョンとは互換性がないものとみなされます。同様に、特に指定がない限り、他のバージョンは新しいバージョンと互換性がありません。実装は、明示的に指定されない限り、バージョン間の互換性があると想定してはなりません(MUST NOT)。
2 つのバージョンの互換性の有無について、両方のエンドポイントで意見が一致しない可能性があることに注意してください。例えば、2 つのバージョンが同時に定義され、その後ずっと後に 3 番目のドキュメントで互換性があると指定される可能性があります。このようなシナリオでは、一方のエンドポイントは互換性ドキュメントを認識している可能性がありますが、もう一方のエンドポイントは認識していない可能性があります。
2.3. 互換バージョンネゴシエーション
サーバーがクライアントの選択バージョンを用いてクライアントの最初のフライトを解析できる場合、クライアントのバージョン情報構造体(セクション3参照)を抽出できます。この構造体には、クライアントが最初のフライトと互換性があると認識しているバージョンのリストが含まれています。
互換バージョンネゴシエーションを実行するために、サーバーはこれらのバージョンのうち、(1) サポートしており、かつ (2) クライアントの選択バージョンと互換性があると認識しているバージョンを1つ選択しなければなりません(MUST)。選択されたバージョンがネゴシエートバージョンとなります。サーバーは、選択した後、クライアントの最初のフライトをそのバージョンに変換しようと試み、変換された最初のフライトを受信したかのようにクライアントに応答します。
ネゴシエートバージョンとクライアントの選択バージョンが同じ場合のように、これらのフォーマットが同一である場合、これは恒等変換となります。最初のフライトが正しくフォーマットされている場合、最初のフライトが互換性があるという定義により、この変換プロセスは失敗しません。サーバーが最初のフライトを変換できない場合、ハンドシェイクを中止しなければなりません(MUST)。
ある文書において、QUICのバージョンが他のバージョンと互換性があると規定されている場合、その文書はクライアントがネゴシエートバージョンを認識できるメカニズムを規定しなければなりません(MUST)。このようなメカニズムの例として、クライアントがQUICロングヘッダーのバージョンフィールドを調べてサーバーのネゴシエートバージョンを判別することが挙げられます。この例のメカニズムでは、サーバーがネゴシエートバージョンに切り替える前に、クライアントの選択バージョンでパケットを送信する可能性があることに注意してください(これは、クライアントのバージョン情報構造が複数のパケットにまたがる場合に発生する可能性があります。その場合、サーバーは最初のパケットをクライアントの選択バージョンで確認応答し、後で別のネゴシエートバージョンに切り替える可能性があります)。相互に互換性のあるバージョンは、同じメカニズムを使用するべきです(SHOULD)。
最初のフライトがネゴシエートバージョンに変換された後、ハンドシェイクはネゴシエートバージョンで完了することに注意してください。ネゴシエートバージョンにハンドシェイク中に適用される要件がある場合、それらの要件は変換された最初のフライトを含むハンドシェイク全体に適用されます。特に、ネゴシエートバージョンがエンドポイントにハンドシェイクパケットの検証を義務付けている場合、エンドポイントは変換された最初のフライトでも同様の検証を行わなければなりません(MUST)。例えば、ネゴシエートバージョンがハンドシェイク全体を通して5タプルが安定していることを要求している場合(QUICバージョン1のように)、両方のエンドポイントは、変換された最初のフライトを含む、ハンドシェイク中に受信したすべてのパケットの5タプルを検証する必要があります。
また、クライアントはバージョン情報の「利用可能なバージョン」フィールドに「選択されたバージョン」のみを含めることで、互換バージョンネゴシエーションを無効にすることもできます(セクション3を参照)。
サーバーが互換バージョン(クライアントの選択バージョンを含む)を見つけられない場合、代わりに非互換バージョンネゴシエーションを実行します(セクション2.1を参照)。
非互換バージョンネゴシエーションの後に互換バージョンネゴシエーションが行われる可能性があることに注意してください。例えば、バージョンAがバージョンBと互換性があり、バージョンCがバージョンDと互換性がある場合、以下のシナリオが発生する可能性があります。
code:図1:複合ネゴシエーションの例
クライアント サーバー
選択 = A, 利用可能なバージョン = (A, B) ------------->
<------------------ バージョンネゴシエーション = (D, C)
選択 = C, 利用可能なバージョン = (C, D) ------------->
<------------- 選択 = D, 利用可能なバージョン = (D, C)
この例では、クライアントはサーバーのバージョンネゴシエーションパケットからCを選択しましたが、サーバーはDを優先し、クライアントのオファーからDを選択しました。
2.4. 接続とバージョンネゴシエーション
QUIC接続は、クライアントとサーバー間で共有される状態ですQUIC-INVARIANTS。本文書で定義される互換バージョンネゴシエーションメカニズム(セクション2.3参照)は、単一のQUIC接続の一部として実行されます。つまり、クライアントの選択バージョンを持つパケットは、ネゴシエートバージョンを持つパケットと同じ接続の一部となります。
これに対し、QUICバージョンネゴシエーションパケット(セクション2.1参照)を利用する非互換バージョンネゴシエーションメカニズムは、概念的には2つのQUIC接続にまたがって動作します。つまり、バージョンネゴシエーションパケットを受信する前の接続試行は、その後に続く非互換バージョンを持つ接続とは区別されます。
なお、この2つの接続間の分離は概念的なものであり、QUIC接続に関する規範的な要件には適用されますが、実装において内部的に2つの異なる接続オブジェクトを使用する必要はありません。
2.5.クライアントによるオリジナルバージョンの選択
クライアントがオリジナルバージョンを選択する際、往復処理を省くため、互換性のないバージョンとのネゴシエーションを避けるように努めるべきです(SHOULD)。したがって、クライアントは、以下の両方の条件を満たす可能性を最大化するために、オリジナルバージョンを選択すべきです(SHOULD)。
サーバーがオリジナルバージョンから最初のフライトを解析する方法を知っていること。
オリジナルバージョンがクライアントの優先バージョンと互換性があること。
追加情報がない場合、クライアントがサポートする最も古いバージョンを選択し、クライアントの最初のフライトではより新しい互換性のあるバージョンをアドバタイズしてしまう可能性があります。
3. バージョン情報
ハンドシェイク中、エンドポイントは選択されたバージョンと利用可能なバージョンのリストからなるバージョン情報を交換します。このメカニズムをサポートするQUICのバージョンは、ハンドシェイク中に双方向でバージョン情報を交換し、このデータが認証されるメカニズムを提供しなければなりません(MUST)。
QUICバージョン1では、バージョン情報は新しいversion_informationトランスポートパラメータを使用して送信されます(QUICのセクション7.4を参照)。バージョン情報の内容は以下の通りです(QUICのセクション1.3の表記を使用)。
code:図2: バージョン情報の形式
Version Information {
Chosen Version (32),
Available Versions (32) ...,
}
各フィールドの内容は以下のとおりです。
Chosen Version(選択されたバージョン):
送信者がこの接続に使用することを選択したバージョン。ほとんどの場合、このフィールドは、このデータを伝送するロングヘッダーの Version フィールドの値と同じになります。ただし、将来のバージョンまたは拡張では、ロングヘッダーの Version フィールドに異なる値が設定される可能性があります。
Available Version(利用可能なバージョン)フィールドの内容は、クライアントから送信されるか、サーバーから送信されるかによって異なります。
クライアントから送信される Available Version(利用可能なバージョン):
クライアントから送信される場合、Available Versionフィールドには、この最初のフライトで互換性のあるすべてのバージョンが、優先度の降順でリストされます。クライアントが選択されたバージョンの優先度を通知できるように、Chosen Versionフィールドのバージョンはこのリストに含まれていなければなりません。この優先度はあくまでも参考値であり、サーバーは独自の優先度を使用することも選択できます。
サーバーから送信されるAvailable Version(利用可能なバージョン):
サーバーから送信される場合、Available Versionフィールドには、このサーバー展開のすべての完全展開バージョンがリストされます (セクション 5 を参照)。このフィールドにおけるバージョンの順序付けには意味はありません。Chosen Version フィールドのバージョンは、サーバー運用者がこのバージョンのサポートを削除中である可能性があるため、必ずしもこのリストに含まれるとは限りません。同様の理由から、Available Versions フィールドは空でも構いません。
クライアントとサーバーはどちらも、0x?a?a?a?a というパターンに続くバージョンを Available Versions リストに含めることができます。これらのバージョンはバージョンネゴシエーション(QUIC のセクション 15 を参照)のために予約されており、使用するバージョンを選択する際に選択されることはありません。
4. バージョンダウングレードの防止
バージョンダウングレードとは、悪意のあるエンティティがQUICエンドポイントに、攻撃が行われなかった場合とは異なるQUICバージョンをネゴシエートさせる攻撃です。このドキュメントで説明するメカニズムは、ダウングレード攻撃を防止するために設計されています。
クライアントは、受信したオリジナルバージョンを含むバージョンネゴシエーションパケットを無視しなければなりません。バージョンネゴシエーションパケットから受信した情報に基づいて接続を試みるクライアントは、その接続試行に対する応答として受信したバージョンネゴシエーションパケットを無視しなければなりません。
両方のエンドポイントは、ハンドシェイク中に相手側のバージョン情報を解析しなければなりません。解析に失敗した場合(例えば、バージョン情報が短すぎる場合や4で割り切れない場合)、エンドポイントは接続を切断しなければなりません。接続がQUICバージョン1を使用していた場合、その接続の切断ではTRANSPORT_PARAMETER_ERRORタイプのトランスポートエラーを使用する必要があります。エンドポイントが「選択バージョン」が0、または「利用可能なバージョン」が0を受信した場合、解析失敗として処理しなければなりません(MUST)。サーバーが「選択バージョン」が「利用可能なバージョン」に含まれていないバージョン情報を受信した場合、解析失敗として処理しなければなりません(MUST)。
バージョンネゴシエーションをサポートするすべてのQUICバージョンは、バージョンネゴシエーションエラーで接続を閉じる方法を定義しなければなりません(MUST)。QUICバージョン1の場合、バージョンネゴシエーションエラーは、VERSION_NEGOTIATION_ERRORタイプのトランスポートエラーを使用して通知されます(セクション10.2を参照)。
サーバーがクライアントの最初のフライトを受信すると、サーバーはまず、最初のフライトを適切に解析するために、この接続で使用されているQUICバージョンを確認します。これには、パケットヘッダーの一部など、ハンドシェイクトランスクリプトの一部ではないデータの検査が含まれる場合があります。サーバーがクライアントのバージョン情報を処理する際、サーバーはクライアントの選択バージョンが接続で使用されているバージョンと一致することを検証しなければなりません(MUST)。両者が異なる場合、サーバーはバージョンネゴシエーションエラーを発生して接続を切断しなければなりません(MUST)。
QUICバージョン1の場合、サーバーは受信した最初のロングヘッダーパケットのバージョンフィールドが0x00000001に設定されていることを確認することで、バージョン1が使用されていると判断します。その後、サーバーがQUICバージョン1でクライアントのバージョン情報(トランスポートパラメータを伝送したロングヘッダーパケットのバージョンフィールドで示される)を受信し、クライアントの選択バージョンが0x00000001に設定されていない場合、サーバーはバージョンネゴシエーションエラーを発生して接続を切断しなければなりません(MUST)。
サーバーは、バージョン情報が欠落している場合でもハンドシェイクを完了して構いません(MAY)。クライアントは、バージョンネゴシエーションパケットに応答する際にバージョン情報が欠落している場合はハンドシェイクを完了してはなりません(MAY)。ただし、それ以外の場合はハンドシェイクを完了しても構いません(MAY)。
クライアントがバージョン情報を受信したときに、サーバーの選択バージョンがクライアントの利用可能なバージョンの一部として送信されていない場合、クライアントはバージョンネゴシエーションエラーで接続を切断しなければなりません(MUST)。クライアントがバージョンネゴシエーションパケットに反応し、サーバーのバージョン情報が欠落していた場合、クライアントはバージョンネゴシエーションエラーで接続を切断しなければなりません(MUST)。
クライアントがバージョンネゴシエーションパケットを受信してそれに応じた場合、クライアントはサーバーの利用可能なバージョンフィールドを検証しなければなりません(MUST)。利用可能なバージョンフィールドの検証は、サーバーがサポートするバージョンをクライアントが認識していた場合、同じバージョンを試行したであろうことを確認することで行われます。つまり、サーバーの利用可能なバージョンフィールドに記載されているバージョンとネゴシエーションバージョンがリストされたバージョンネゴシエーションパケットを受信した場合、クライアントは同じバージョンを選択したはずです。クライアントが異なるバージョンを選択した場合、クライアントはバージョンネゴシエーションエラーで接続を切断しなければなりません(MUST)。特に、クライアントがバージョンネゴシエーションパケットに反応し、サーバーの「利用可能なバージョン」フィールドが空の場合、クライアントはバージョンネゴシエーションエラーで接続を閉じる必要があります。これらの接続の切断により、攻撃者が偽造されたバージョンネゴシエーションパケットを使用して強制的にバージョンダウングレードを行うことを防止できます。
例として、クライアントが仮想的なQUICバージョン10、12、14をサポートし、上位バージョンを優先していると仮定します。クライアントはバージョン12で接続を試行します。2つの独立したシナリオ例を見てみましょう。
最初のシナリオでは、サーバーはバージョン10、13、14をサポートしていますが、13と14のみがFully Deployedです(セクション5を参照)。サーバーはバージョン10、13、14を含むバージョンネゴシエーションパケットを送信します。これにより互換性のないバージョンネゴシエーションが発生し、クライアントはバージョン14で新しい接続を開始します。すると、サーバーのAvailable Versionsフィールドにはバージョン13と14が含まれます。このシナリオでは、クライアントはバージョン13と14を含むバージョンネゴシエーションパケットを受信していた場合、バージョン14を選択したはずです。そのため、ネゴシエートされたバージョン14を使用してハンドシェイクは成功します。
2番目のシナリオでは、サーバーはバージョン10、13、14をサポートしており、それらはすべてFully Deployedです。しかし、攻撃者はバージョン10と13を含むバージョンネゴシエーションパケットを偽造します。これにより互換性のないバージョンネゴシエーションが発生し、クライアントはバージョン10で新しい接続を開始します。すると、サーバーの「利用可能なバージョン」フィールドには10、13、14が含まれます。このシナリオでは、クライアントはバージョン10、13、14を含むバージョンネゴシエーションパケットを受信していた場合、10ではなく14を選択するため、バージョンネゴシエーションエラーでハンドシェイクを中止します。
この「利用可能なバージョン」の検証だけでは、ダウングレードを防ぐのに十分ではありません。ダウングレードの防止は、クライアントが「元のバージョン」を含むバージョンネゴシエーションパケットを無視することにも依存します(セクション2.1を参照)。
本文書で説明されているバージョンネゴシエーションプロセスが完了すると、接続で使用されるバージョンは、サーバーがバージョン情報の「選択バージョン」フィールドで送信したバージョンになります。これは、接続の存続期間中のどの時点でも、ロングヘッダーのバージョンフィールドで他のバージョンが使用されていた場合であっても当てはまります。特に、互換性のあるバージョンネゴシエーション(セクション2.3参照)中に、クライアントはQUICロングヘッダーのバージョンからネゴシエートバージョンを知ることができるため、クライアントはサーバーの「選択バージョン」がネゴシエートバージョンと一致することを検証しなければなりません(MUST)。一致しない場合、クライアントはバージョンネゴシエーションエラーで接続を切断しなければなりません(MUST)。これにより、攻撃者がロングヘッダーのバージョンフィールドを偽造してバージョンネゴシエーションに影響を与えることを防ぎます。
5. QUIC のサーバー展開
このドキュメントでは主に単一の QUIC サーバーについて説明していますが、QUIC サーバーの展開では複数のサーバーインスタンスで構成されることが一般的です。そのため、以下の用語を定義します。
Acceptable Versions(許容バージョン):
これは、特定のサーバーインスタンスがサポートするバージョンのセットです。より具体的には、クライアントがこれらのバージョンを使用して最初のフライトを送信した場合に、特定のサーバーインスタンスが使用するバージョンのセットです。
Offered Versions(提供バージョン):
これは、特定のサーバーインスタンスが不明なバージョンからの最初のフライトを受信した場合、バージョンネゴシエーションパケットで送信するバージョンのセットです。このセットは、バージョンが追加または削除される短い遷移期間(下記参照)を除き、ほとんどの場合、許容バージョンセットと一致します。
Fully Deployed Versions(完全に展開されたバージョン):
これは、この展開内のすべての QUIC サーバーインスタンスによってサポートされ、ネゴシエートされる QUIC バージョンのセットです。デプロイメントにサーバーインスタンスが1つしか含まれていない場合、このセットは、バージョンの追加または削除中の短い遷移期間(下記参照)を除き、Offered Versions セットと等しくなります。
デプロイメントに複数のサーバーインスタンスが含まれている場合、ソフトウェア更新はすべてのサーバーインスタンスで同時に行われない可能性があります。そのため、クライアントが既に更新済みのサーバーインスタンスからバージョンネゴシエーションパケットを受信し、その結果としてクライアントが接続を試行した結果、まだ更新されていない別のサーバーインスタンスに到達する可能性があります。
ただし、サーバーインスタンスが1つしかない場合でも、バージョンネゴシエーションパケットの送信中にサーバーがソフトウェア更新を実行すると、古いバージョンネゴシエーションパケットを受信する可能性があります。
これにより、セクション4で説明されているバージョンダウングレード防止メカニズムがダウングレード攻撃を誤検出する可能性があります。これを回避するため、サーバー運用者は、バージョンのサポートを追加または削除する際に、下記に説明する3段階のプロセスを実行する必要があります(SHOULD)。
新しいバージョンのサポートを追加する場合:
最初のステップは、すべてのサーバーインスタンスに新しいバージョンのサポートを段階的に追加することです。このステップでは、許容バージョンは更新されますが、提供バージョンと完全デプロイバージョンは更新されません。すべてのサーバーインスタンスが更新されたら、オペレーターは少なくとも1つのMSLが処理中のバージョンネゴシエーションパケットの到着を許可するまで待機します。
次に、2番目のステップとして、すべてのサーバーインスタンスの「提供バージョン」に新しいバージョンを段階的に追加します。完了したら、オペレーターは少なくとももう1つのMSLを待機します。
最後に、3番目のステップとして、すべてのサーバーインスタンスの「完全デプロイバージョン」に新しいバージョンを段階的に追加します。
バージョンのサポートを削除する場合:
最初のステップとして、すべてのサーバーインスタンスの「完全デプロイバージョン」からそのバージョンを段階的に削除します。すべてのサーバーインスタンスでバージョンが削除されたら、オペレーターは少なくとも1つのMSLが処理中のバージョンネゴシエーションパケットの到着を許可するまで待機します。
次に、2番目のステップとして、すべてのサーバーインスタンスの「提供バージョン」から該当バージョンを段階的に削除します。削除が完了すると、オペレーターは少なくとも次のMSLを待機します。
最後に、3番目のステップとして、すべてのサーバーインスタンスから該当バージョンのサポートを段階的に削除します。このステップにより、「受け入れ可能バージョン」が更新されます。
更新期間中は、接続は「完全にデプロイされていない受け入れ可能バージョン」に対するダウングレード攻撃に対して脆弱であることに注意してください。これは、クライアントが、このようなダウングレード攻撃と、更新されたサーバーインスタンスと更新されていないサーバーインスタンスの両方との正当な通信を区別できないためです。
6. アプリケーション層プロトコルに関する考慮事項
クライアントがQUIC接続を確立する際、その目的はアプリケーション層プロトコルを使用することです。したがって、互換性のあるバージョンを検討する際、クライアントは対象となるアプリケーション層プロトコルのいずれかをサポートするバージョンのみを検討します。クライアントの最初のフライトで複数のアプリケーション層プロトコルネゴシエーション(ALPN)ALPNトークンと複数の互換性のあるバージョンがアドバタイズされた場合、一部のアプリケーション層プロトコルは、提供されている互換性のあるバージョンの一部では動作しない可能性があります。サーバーは、選択した互換性のあるQUICバージョンで動作可能なALPNトークンのみを選択する責任があります。
以下のすべての要件を満たさない限り、特定のALPNトークンは、そのALPNトークンが元々定義されたバージョンとは異なる新しいQUICバージョンで使用してはなりません。
新しいQUICバージョンは、アプリケーションプロトコルに必要なトランスポート機能をサポートしています。
新しいQUICバージョンはALPNをサポートしています。
ALPNトークンが元々定義されたQUICのバージョンは、新しいQUICバージョンと互換性があります。
互換性のないバージョンネゴシエーションが使用されている場合、受信したバージョンネゴシエーションパケットに応答して確立される2番目の接続は、元のバージョンを考慮せずに、アプリケーション層プロトコルネゴシエーションプロセスを再開する必要があります。
7. 将来のバージョンに関する考慮事項
将来のQUICバージョンの導入を容易にするために、将来のバージョンの設計者は、一般的に導入されているバージョンと互換性があるように新しいバージョンを設計するよう努めるべきです。
QUICバージョン1では、QUIC不変条件に記載されていない複数の機能が定義されています。執筆時点では、QUICバージョン1が広く導入されているため、このセクションでは、QUICバージョン1との互換性を確保するための将来のバージョンに関する考慮事項について説明します。
7.1. リトライとの相互作用
QUIC バージョン 1 は、クライアントの最初のフライトを解析する前に、サーバーがクライアントの IP アドレスを検証するために送信できるリトライパケットを備えています。リトライパケットを送信するサーバーは、クライアントの最初のフライトを解析する前に送信できます。そのため、リトライパケットを送信するサーバーは、クライアントのバージョン情報を処理していない可能性があります。
将来、リトライをサポートする 2 つのバージョン間の互換性を定義する文書を作成する場合、その文書では、バージョンネゴシエーション(互換バージョンと非互換バージョンの両方)がリトライを必要とするハンドシェイク中に、リトライとどのように相互作用するかを規定する必要があります。例えば、サーバーが最初にオリジナルバージョンでリトライパケットを送信し、互換バージョンネゴシエーションを試みる前にクライアントの IP アドレスを検証することで、これを実現できます。両方のバージョンが認証付きリトライパケットをサポートしている場合、リトライ自体はクライアントの選択バージョンを使用して送信されたとしても、ネゴシエートバージョンハンドシェイクでリトライを認証する方法を互換性定義で定義する必要があります。
7.2. TLS 再開との相互作用
QUIC バージョン 1 は TLS 1.3 を使用します。TLS 1.3 は、ある接続でセッションチケットを送信し、それを後の接続で使用できるようにするという方法でセッション再開をサポートします (TLS のセクション 2.2 を参照)。TLS 1.3 も使用する新しいバージョンでは、セッションチケットが QUIC の 1 つのバージョンに厳密に限定されることを義務付けるべきです (SHOULD)。つまり、クライアントが複数のバージョン間でセッションチケットを使用しないこと、そしてサーバーがこのクライアント要件を検証することを義務付けるべきです (SHOULD)。これは、クロスプロトコル攻撃の軽減に役立ちます。
7.3. 0-RTT との相互作用
QUIC バージョン 1 では、ハンドシェイク中に 0-RTT パケットを使用してクライアントからサーバーにデータを送信できます。将来の文書で 0-RTT をサポートする 2 つのバージョン間の互換性を定義する場合、その文書では、クライアントの最初のフライトに 0-RTT パケットが存在するシナリオに対応する必要があります (MUST)。例えば、0-RTT パケットに適用される変換を定義することでこれを実現できます。このドキュメントでは、互換性のあるバージョンのネゴシエーションにより、0-RTT データがサーバーによって拒否されることを指定できます。
8. QUIC バージョン 1 の特別な処理
QUIC バージョン 1 は、本文書より前に IETF 標準化委員会で公開されていた唯一の QUIC バージョンであったため、以下のように特別な処理が行われます。クライアントが受信したバージョンネゴシエーションパケットへの応答として QUIC バージョン 1 接続を開始し、サーバーのトランスポートパラメータに version_information トランスポートパラメータが含まれていない場合、クライアントは、サーバーのトランスポートパラメータに、選択されたバージョンが 0x00000001 に設定され、使用可能なバージョンリストに 0x00000001 に設定されたバージョンが 1 つだけ含まれているバージョンが含まれているかのように処理を進めるものとします (SHALL)。これにより、QUIC バージョン 1 のみをサポートするサーバーでもバージョンネゴシエーションが機能します。QUIC バージョン 1 以外のバージョンをネゴシエートするためにバージョンネゴシエーションを使用する実装は、本文書で定義されているバージョンネゴシエーションメカニズムを実装する必要があることに注意してください。
9. セキュリティに関する考慮事項
このバージョンネゴシエーションメカニズムのセキュリティは、ハンドシェイク中に交換されるバージョン情報の真正性に依存します。QUICバージョン1では、トランスポートパラメータが認証されるため、このメカニズムのセキュリティが確保されます。互換性のあるバージョン間のネゴシエーションでは、最も弱い共通バージョンのセキュリティが適用されます。
バージョン間の互換性を前提としないという要件は、クロスプロトコル攻撃の可能性を軽減しますが、この点についてはさらなる分析が必要です。この分析は本文書の範囲外です。
10. IANAに関する考慮事項
10.1. QUICトランスポートパラメータ
IANAは、< https://www.iana.org/assignments/quic >で管理されている「QUICトランスポートパラメータ」レジストリに以下の値を登録しました。
値:
0x11
パラメータ名:
version_information
ステータス:
permanent
仕様:
RFC 9368
10.2. QUIC トランスポート エラーコード
IANA は、< https://www.iana.org/assignments/quic > で管理されている「QUIC トランスポート エラーコード」レジストリに以下の値を登録しました。
値:
0x11
コード:
VERSION_NEGOTIATION_ERROR
説明:
バージョンネゴシエーションエラー
ステータス:
永続的
仕様:
RFC 9368
11. 参考文献
11.1. 規範的な参考文献
ALPN
Friedl, S., Popov, A., Langley, A., and E. Stephan, "Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301, July 2014, < https://www.rfc-editor.org/info/rfc7301 >.
QUIC
Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, May 2021, < https://www.rfc-editor.org/info/rfc9000 >.
QUIC-INVARIANTS
Thomson, M., "Version-Independent Properties of QUIC", RFC 8999, DOI 10.17487/RFC8999, May 2021, < https://www.rfc-editor.org/info/rfc8999 >.
RFC2119
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, < https://www.rfc-editor.org/info/rfc2119 >.
RFC8174
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, < https://www.rfc-editor.org/info/rfc8174 >.
TLS
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, < https://www.rfc-editor.org/info/rfc8446 >.
11.2. 有益な文献
TCP
Eddy, W., Ed., "Transmission Control Protocol (TCP)", STD 7, RFC 9293, DOI 10.17487/RFC9293, August 2022, < https://www.rfc-editor.org/info/rfc9293 >.
謝辞
著者一同は、Nick Banks、Mike Bishop、Martin Duke、Ryan Hamilton、Roberto Peon、Anthony Rossi、Martin Thomsonの各氏からいただいたご意見とご貢献に感謝申し上げます。
著者の連絡先
David Schinazi
Google LLC
1600 Amphitheatre Parkway
Mountain View, CA 94043
アメリカ合衆国
メールアドレス: dschinazi.ietf@gmail.com
Eric Rescorla
Mozilla
メールアドレス: ekr@rtfm.com