要約

  • ALPNはアプリケーションプロトコルの選択をTLSハンドシェイクに収め、共通ポート上で別の交渉往復を増やさないようにした。
  • クライアントは順序付きの候補を出すが、サーバーはその共通部分から一つを自分の方針で選ぶ。共通項がなければ、アプリケーションデータより前に致命的アラートで終える。
  • 選択は一つの接続にだけ有効で、再開可能なTLSセッションには属さない。HTTP/2のプリフェイス、0-RTTの条件、QUICのバージョン整合性は、その境界を別々の角度から確認する。

h2の後にも最初の言葉が必要だった

TLSがh2を返した時点で、双方はHTTP/2を使うことに同意している。それでも RFC 9113 は、ハンドシェイク完了後にクライアントとサーバーの両方へ接続プリフェイスを要求する。クライアントは特徴的なオクテット列とSETTINGS、サーバーはSETTINGSから始める。

二つの仕組みは重複していない。ALPNは、どの文法がこの保護された接続を受け取ってよいかを選ぶ。プリフェイスは、実際に接続されたアプリケーションがその文法で始まり、初期パラメーターを交換できることを確かめる。

この区別は障害時に効く。エッジのTLS終端装置が正しくh2を選んでも、誤ったバックエンドへストリームを渡せばプリフェイスが壊れる。ALPNログだけなら「HTTP/2成功」に見え、アプリケーションログだけなら不正な先頭バイトに見える。両方を同じ接続として残して初めて、選択後の引き渡しが失敗したと分かる。

h2cは平文HTTP/2用の古い識別子であり、TLS ALPNでは送信も選択もしてはならない。名前が登録簿に残ることと、その文脈で利用が許されることも同じではない。

ポートから文法を推測する時代の限界

ポート番号は長くアプリケーションの実用的な目印だった。TLS上で複数プロトコルが同じ接続先、特に443を共有すると、その目印だけでは足りない。暗号化後に追加の交渉を行えば一往復増える。最初のデータを見てプロトコルを推測すれば、誤ったパーサーがすでにバイトを受け取る。

RFC 7301 は選択をTLSハンドシェイクに移した。クライアントはClientHelloで自分が理解できる不透明な識別子を並べ、サーバーはその中から一つを返す。アプリケーションが最初のメッセージを出す前に、接続の文法が決まる。

RFC 8170 はHTTP/2移行の経験として、TLS版にはALPN、非保護版にはアップグレードが使われたと記録する。ALPNは追加往復を避け、将来のHTTPバージョン交渉の主要な経路になった。

HTTPアップグレードは既存のHTTP/1.1メッセージで提案と101応答を交わし、同じストリームの途中に文法変更点を作る。ALPNはアプリケーションメッセージより前に、TLS接続確立の一部として選ぶ。似ているのは「共通プロトコルを決める」ことだけで、証拠の位置も中継装置に対する範囲も異なる。

提示の順序と判断の順序

クライアントのProtocolNameListは優先順位順である。各名前は空でない不透明バイト列で、途中で切り詰めてはならない。人間がh2と読める例があっても、通信路上の比較は登録済みバイトの一致である。

一方、サーバーも対応と優先順位を持つ。RFC 7301は、クライアントが提示したものの中からサーバーが最も好む共通プロトコルを選ぶことを想定する。クライアントの一番目が自動的に勝つわけではない。

この二重の優先順位は自治を残す。クライアントは「これ以外は解析できない」という集合を決める。サーバーはその内側で「今回はこれを提供する」と決める。サーバーは未提示の値を発明できず、クライアントはサーバーの運用方針を上書きできない。

返答は一つである。その選択は接続に対して確定的であり、サーバーは選んだプロトコルと異なるアプリケーションデータを後から使えない。能力通知ではなく、次のバイトの意味を一つに固定する約束だからである。

共通項がない時、プリフェイスまで進まない

サーバーがクライアントの候補を一つも扱えない場合、no_application_protocol致命的アラートを返す。古い文法へ黙って落ちる方が親切に見えることもある。しかしクライアントが承認していない文法を既定値にすれば、同じ暗号化されたストリームを双方が違う形式で読む可能性が生まれる。

明示的な失敗は、証明書エラー、パケット損失、アプリケーション拒否、プリフェイスエラーと区別できる。まだアプリケーション状態が作られていないため、運用者は候補や優先順位を直し、別の接続方針を試す余地を持つ。

RFC 9325 は現代的TLS実装にALPN対応を要求し、提示集合にないプロトコルを選ばず、共通項がなければ規定どおり失敗することを強く勧める。背景にはプロトコル間の混同がある。あるサービス用のメッセージが別サービスに有効な命令として解釈され得るからだ。

ALPN選択があっても認証や認可が完成するわけではない。だが選択を無視すれば、どのパーサーに渡すかという最初の防波堤まで失う。

チケットは新しい接続の回答を持っていなかった

セッション再開は以前の暗号処理状態を利用してハンドシェイクの仕事を減らす。前の接続がh2なら、その選択もチケットに保存したくなる。

RFC 7301は反対の範囲を明記した。ALPNはセッションではなく接続の属性である。セッションチケットや再開を使っても、以前の拡張内容は無関係で、新しいハンドシェイクの値だけが有効になる。

クライアントがプロトコルを廃止したかもしれない。サーバーが優先順位を変えたかもしれない。チケットは別のノードで受け取られるかもしれない。古い選択を強制すれば、暗号処理の最適化がアプリケーション展開の決定権を持ってしまう。

そのため「再開済みなのに別プロトコル」は単独では障害を意味しない。二つの接続の提示、選択済み値、ノード、方針バージョンを比べる必要がある。チケットの系譜は比較の関連手掛かりであり、新しい記録へ前の答えを転記する命令ではない。

TLS 1.3ではサーバーの答えが奥へ移った

RFC 7301の時代、クライアント提示とサーバー選択はそれぞれClientHelloとServerHelloに置かれ、ネットワーク装置から見える設計だった。ポートがプロトコルを示さない時にサービスの振り分けを行うためである。同時に、識別子が個人情報やプロファイリングの手掛かりになり得ると警告した。

RFC 8446 のTLS 1.3では、サーバーのALPN応答はEncryptedExtensionsに入る。これはサーバーハンドシェイクトラフィック秘密値由来の鍵で暗号化される最初のメッセージである。クライアント提示は通常のClientHelloに残る。

したがってパケット取得記録の説明にはTLSバージョンと方向が必要だ。「ALPNは平文」も「TLS 1.3なら全部隠れる」も広すぎる。サーバーの選択は保護されるようになったが、クライアントの意図を示す候補が同じ方法で消えたわけではない。

可視性が変わっても接続範囲は変わらない。見えにくくなった答えも、セッションチケットの属性にはならず、新しいハンドシェイクの中で改めて決まる。

0-RTTは同じ名前だけでは安全にならない

TLS 1.3再開では、条件を満たすクライアントがハンドシェイク完了前に早期データを送れる。このバイトは前回と同じアプリケーション文脈を期待して準備されるため、新しいALPN選択が違えば意味の土台が崩れる。

RFC 8446は、交渉後の接続が同じALPNプロトコルを選ばない限り、TLS実装が早期データを自動再送してはならないとする。HTTP/2用フレームをHTTP/1.1接続へ機械的に移すことはできない。

同じALPNは必要条件にすぎない。同じプロトコルでも操作が既に処理されたかもしれず、認証情報やリソース状態が変わっているかもしれない。再実行の許否はアプリケーションが判断する。TLSが持つのは、少なくとも文法が違う時には再送できないという狭い権限である。

ここでも選択と認可を混ぜないことが重要だ。ALPNが同じであることは、リクエストの再実行やオリジンへのアクセスを許可しない。

QUICはトランスポートバージョンとの整合も求めた

RFC 9001 はQUICの暗号処理ハンドシェイクに認証されたアプリケーションプロトコル交渉を求め、別の仕組みがなければALPNを使う。アプリケーションプロトコルが決まらない接続は即座に閉じる。

さらにアプリケーションプロトコルは利用可能なQUICバージョンを限定できる。サーバーはクライアントが選んだQUICバージョンと両立するプロトコルを選び、クライアントも不整合な組合せを拒否する。

つまり名前の一致だけでは十分でない。クライアント対応、サーバー方針、トランスポートバージョンが同時に交わる必要がある。ALPNは中央調整役ではなく、二つの接続先がその接続上で共通事実を作るための通信路上の契約である。

HTTP/3やQUIC上のドメイン名システムなど別々のアプリケーションが同じトランスポートを利用できるのは、ポートやチケットがすべてを決めるからではない。接続ごとの選択がアプリケーション状態の前に失敗できるからである。

登録簿はプロトコルの存在証明ではない

IANAのTLS拡張・ALPNプロトコル識別子登録簿 は拡張タイプ16と不透明識別子を管理する。http/1.1、h2、h3のほか、TLS ALPNでは禁止されるh2cも境界付きで残る。

登録はバイト列の衝突を防ぎ、仕様への参照を固定する。現在のクライアントが提示すること、サーバーが選択すること、トラフィックが流れること、実装が安全であることは証明しない。

運用証拠には順番がある。登録簿は名前の割当を示す。ハンドシェイクは一つの接続の提示と選択を示す。プリフェイスはアプリケーションが選択を実行したことを示す。その後の認可ログが操作の許可を示す。

一つの証拠を次の証拠の代わりにしないことが、ALPNの小さな約束を強くした。チケットは戻れても、プロトコルの選択は戻らない。新しい接続は、自分が受け取る最初の言葉を自分のハンドシェイクで決める。

出典

これらは標準、推奨、登録状態の資料であり、現在の導入比率や特定製品の動作を測定した資料ではない。