[メモ] HTTP/2 における connection reuse の挙動について調べた
こんなことがあった
[環境]
a.example.com -> DNS A record: X.X.X.X (origin A)
b.example.com -> DNS A record: Y.Y.Y.Y (origin B)
※どちらも *.example.com
のワイルドカード証明書を使っていて、接続はTLSとする
HTTP/2 が有効な上記のサービスにおいて、エンドユーザがlocal networkにProxyを持っている場合(社内プロキシなど)に b.example.com が a.example.com のコネクションを再利用し、origin A
は当然 b.example.com
のコンテンツを持っていないので意図しないレスポンスが返ってしまう、といったことが起きた。
それぞれIPアドレスは違うのに、どうしてだろう?
RFC 7540
RFCには、TLSコネクションについては名前解決結果を問わないとされている。
Connections that are made to an origin server, either directly or
through a tunnel created using the CONNECT method (Section 8.3), MAY
be reused for requests with multiple different URI authority
components. A connection can be reused as long as the origin server
is authoritative (Section 10.1).
HTTP/2 relies on the HTTP/1.1 definition of authority for determining
whether a server is authoritative in providing a given response (see
[RFC7230], Section 9.1). This relies on local name resolution for
the "http" URI scheme and the authenticated server identity for the
"https" scheme (see [RFC2818], Section 3).
つまり、今回の例で考えると、まずユーザがa.example.com
にアクセスし、その際に*.example.com
のワイルドカード証明書を受け取ります。この証明書は当然 b.example.com
に対しても有効であるので、RFC上はそれぞれのIPアドレスが違ったとしても厳密にチェックを行うことを必須としておらず、このワイルドカード証明書をもとにa.example.com
へのアクセスで確立したコネクションを再利用し、b.example.com
のリクエストをorigin A
へ要求しても問題はないことになっているのです。
知らなかった。。。
ブラウザはきちんと制御してくれる
手元でも同様の環境を用意して試しました。ユーザが直接それぞれのoriginへ接続しにいく構成です。
結論から言うと、各種ブラウザは HTTP/2 + TLS の場合でも、それぞれのドメインの名前解決の結果が一致しない限りはコネクションの再利用を行わないように独自のロジックを実装しているようです。親切ですね。でもこれが余計に私を混乱させたのも事実。
※面白いトピックとしては、FirefoxにはoriginのDNSエントリが IPv4 + IPv6 を含む混在環境において(+ クライアントがIPv6アドレスを持っているる場合)、当初説明したような意図しないコネクション再利用を行う挙動もあったりする。(手元でも再現確認済)
https://bugzilla.mozilla.org/show_bug.cgi?id=1190136
Proxyは実装次第
では今回の問題が起きた構成と同様に、ユーザがlocal Proxyを利用するケースを考えます。
この場合の挙動はProxyの実装次第なので、ブラウザ同様に振る舞われるケースもあれば、特にそこは考慮されずにコネクションが再利用される事もあるということです。意外な落とし穴ですよね。
※当初 HTTP/2 readyのlocal proxyツール(mitmproxy)を使って検証したが、残念ながら問題の事象は再現できなかった。
Webサーバ側で不正なコネクション再利用を検知できないのか
421 - Misdirected Request
RFCでは今回のような場合を考慮し、Webサーバが HTTPステータスコード 421 - Misdirected Request
を返すことが認められています。
https://tools.ietf.org/html/rfc7540#section-9.1.2
これにより、コネクション再利用によってクライアントから要求されたコンテンツをサーバが応答不能である場合にサーバがクライアントへ 421
を返し、これを受け取ったクライアントはコネクションを新たに作成した上でもう一度適切なoriginへ要求をリトライする かもしれない ことになっています。そうです、421を受け取った際の処理はあくまでも MAY であって、リトライを行わずにエラーをそのまま表示する可能性もあります。
またリトライ処理を行ったとしてもその分のperformance影響が避けられません。
ORIGIN Frame
421 には前述したようにいくつか問題があります。そこで期待されているのが、RFC 8336として今年正式に公開されたORIGIN Frameです。
+-------------------------------+-------------------------------+
| Origin-Entry (*) ...
+-------------------------------+-------------------------------+An Origin-Entry is a length-delimited string:
+-------------------------------+-------------------------------+
| Origin-Len (16) | ASCII-Origin? ...
+-------------------------------+-------------------------------+
この拡張仕様では、上記のようにoriginからレスポンスを返す際に明示的にコネクション再利用可能なoriginのリストをクライアントへ渡す事が可能になります。そしてこのOrigin-Entry
にワイルドカードを使うことはできません。
これによってorigin側での制御が可能になり、意図しないコネクション再利用によるエラーを防ぐことができるようになります。
ただし注意したい点としては、このORIGIN Frameもコネクション再利用時にドメインの名前解決を必須としていません。Origin-Entry
にoriginをいくつか列挙する場合は、念のため余計なものが含まれないように注意するべきですね。
Additionally, clients MAY avoid consulting DNS to establish the
connection’s authority for new requests to origins in the Origin Set;
however, those that do so face new risks, as explained in Section 4.
まとめ
RFC読もう。
参考リンク
https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/
https://medium.com/bbc-design-engineering/http-2-is-easy-just-turn-it-on-34baad2d1fb1
https://asnokaze.hatenablog.com/entry/2018/01/11/220418
Author And Source
この問題について([メモ] HTTP/2 における connection reuse の挙動について調べた), 我々は、より多くの情報をここで見つけました https://qiita.com/jrsyo/items/0c0d6dea104a254dc987著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .