要約

  • Upgrade や CONNECT は HTTP/1.1 接続の残りを別のプロトコルへ移したいという要求であり、相手方の受諾そのものではない。
  • 拒否された場合、先に送られたデータは依然として HTTP/1.1 として読まれ得る。

レイテンシーを減らす設計では、待機は常に悪に見える。要求は完了し、クライアントは希望するプロトコルを知っており、過去の接続ではうまくいったかもしれない。そこで最初のデータを先に出す。だが RFC 9931 は、ここで一つの事実が欠けていると指摘する。サーバーはまだ、どの解析規則を採るかを返答していない。

HTTP/1.1 では Upgrade が受け入れられたことは 101 Switching Protocols で、CONNECT が受け入れられたことは成功の 2xx で示される。要求が最後まで送られたことは必要条件にすぎない。サーバーは Upgrade を無視でき、認証を求め、リダイレクトし、宛先を方針または到達不能のため拒否できる。クライアントが持つのは提案の記録であり、次のパーサーを選ぶ権利ではない。

この差は、拒否後にも接続が残り得るため重要になる。RFC 9931 によれば、拒否したサーバーは後続バイトを HTTP/1.1 として解釈し続ける。クライアントが新プロトコルの開始だと思う列が、サーバーには次の HTTP 要求に見えることがある。バイトが自らの意味を決めるのではない。応答が確定するまで、二つの側が異なる文法を待っている。

信頼されるクライアントが、信頼されない第三者由来の内容を運ぶとき、ずれは危険になる。ブラウザーは別オリジンに選ばれたデータを送ることがあり、プロキシのクライアントはローカルアプリケーションの TCP payload を転送することがある。CONNECT が失敗したのに payload を先回りで送れば、プロキシはまだ HTTP/1.1 の文法でそれを読むかもしれない。RFC 9931 は request smuggling やパーサーの前提破りを条件付きの危険として説明する。個別の事件、実装、攻撃成功を証明する文書ではない。

connect-udp の更新は慎重さを実装規則に変える。UDP パケットの楽観的送信は HTTP/2 以降に限られ、HTTP/1.x では禁止される。これは HTTP/2 の正しさを保証する印ではない。宛先、配送、利用者の本人性、サービス結果を語るものでもない。HTTP/1.x に残る解釈の不確実性を、速さのために他者へ渡さないという限定的な選択である。

不信頼な TCP クライアントのために CONNECT を送るプロキシクライアントは、2xx を待ってから payload を転送するか、Connection: close を送らなければならない。拒否したプロキシは、次の要求を処理する前に接続を閉じる。これらは、payload の出所、遷移の選択、接続認証、後続の行為を別々に保つための制御である。

Heng Lu のいう実行中のコードの重みは、ここでむしろ限定を明確にする。実行記録は価値がある。しかし「要求を出した」「応答を見た」「特定のパーサーが読んだ」「下流で効果があった」は別々の記録である。ある層の事実を、まだ観測されていない別の層の決定へ昇格させてはならない。

出典