DNS HTTPSレコードで別ドメインにpreconnectさせる提案仕様

A Preconnect Hint for SVCB/HTTPS RR」という提案仕様がIETFに提出されています

これは、DNS HTTPSレコードを用いて、クライアントに別ドメインに対して事前接続(preconnect)させることを可能にします。

DNS HTTPS レコード

今回使う DNS HTTPSレコード自体はすでに使われてる仕組みです。

やや古い記事ですが、DNSHTTPSレコードについては以前書いたとおりです。
ブラウザがhttpsでサーバに通信する際に有用な情報を名前解決時に提供できるようになります。

asnokaze.hatenablog.com

A Preconnect Hint for SVCB/HTTPS RR

A Preconnect Hint for SVCB/HTTPS RR」の仕組みは具体例があると分かりやすいかと思います。

例えば、https://example.com はページのサブリソースとしてwww.example.comやscripts.example.orgを含むとします。

通常ブラウザは、https://example.com にアクセスしてHTMLをパースしてサブリソースを取得するために、scripts.example.orgに接続しに行きます。

preconnectHint

今回の提案では、HTTPS レコードにpreconnectHintといパラメータを追加します。

example.org IN HTTPS 1 . alpn=h2,h3 preconnectHint=www.example.com,scripts.example.org

クライアントは、example.orgの名前解決する際に合わせてこのレコードを取得し、preconnectHintで指定されたドメインに事前に接続を確立しておきます。

具体的には名前解決とTCP, TLS, QUICなどのハンドシェイクなどまで終わらせておきます(W3C Resource Hints)。そして、将来のHTTPリクエストに備える事ができます。

これにより、サブリソースを取得する際に発生するコネクション確立の待ち時間を減らすことが出来ます。

TLSの復号に用いる SSLKEYLOGFILE のフォーマット提案仕様

QUICやTLS通信のデバッグを行うために、TLS実装が通信に用いたシークレットをファイルに出力することがあります。多くの実装は SSLKEYLOGFILE という形式で出力することが一般的になっています。このファイルをWiresharkなどに食べさせることで該当通信の復号が行なえます。

たとえば、QUICは以前書いた手順で復号できます。
asnokaze.hatenablog.com


SSLKEYLOGFILE のファイル形式は、NSSのドキュメント(URL)で見ることが出来ますが

ちゃんと SSLKEYLOGFILE を仕様化するために「The SSLKEYLOGFILE Format for TLS」という提案がIETFに提出されています。

SSLKEYLOGFILEの中身

例えば OpenSSLでSSLKEYLOGFILE を出力すると次のとおりになる

# SSL/TLS secrets log file, generated by OpenSSL
SERVER_HANDSHAKE_TRAFFIC_SECRET 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 b48d1fdc6b10b6f4765456e8407649b25971f3384e63461bdacab59c2488cacb8bb7dcde0aa1e2c6ede9390b568624f4
EXPORTER_SECRET 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 b56d696bd2fc3ef533dea35a6f907586cbbd7d049fd027d9964d3b924435ea157bfc955a55ef1d6ea7d5012ea906dee3
SERVER_TRAFFIC_SECRET_0 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 4676aa104c6ac82822f4450c5a8d3990f70b64005bed05e50a9586e4cd2a6c0187fec0220a83ed21e69eb61fd9e9cfaf
CLIENT_HANDSHAKE_TRAFFIC_SECRET 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 6ef4d40e4103a2aa00c985a5287314048fdaddd781f7ee90a2b98513efef6fde04a00950721660ba9e5afb184fbafc70
CLIENT_TRAFFIC_SECRET_0 24878b76381f03203d3c4772bf51c49c5786c7adcf7d8fdd644460d5deafd6d5 8408e4b76dfcb3850eea590c8be1a0fb42a5c63f85246b1b6b16661241670f19c0a511b3d683d5bafc650e89efc04890

#で始まる行はコメント行である。

各行の意味

各行は、スペース区切りで「label」「client_random」「secret」の3つが記述される。

  • label: シークレットのタイプを示す識別子
  • client_random: ClientHelloのランダムの値。これによりどのコネクションのシークレットかわかるようになっている。
  • secret: シークレット値
ラベルの種類

TLS1.3で使うlabelは次の種類がある

  • CLIENT_EARLY_TRAFFIC_SECRET: early dataに用いたシークレット
  • EARLY_EXPORTER_MASTER_SECRET: early exportersに用いたシークレット
  • CLIENT_HANDSHAKE_TRAFFIC_SECRET: クライアントが送った handshake レコードに用いたシークレット
  • SERVER_HANDSHAKE_TRAFFIC_SECRET: サーバが送った handshake レコードに用いたシークレット
  • CLIENT_TRAFFIC_SECRET_0: クライアントがapplication_data レコードに用いたシークレット。(数字はKey Updateにより増える)
  • SERVER_TRAFFIC_SECRET_0: サーバがapplication_data レコードに用いたシークレット。(数字はKey Updateにより増える)
  • EXPORTER_SECRET: exportersに用いたシークレット

CookieのPartitioned属性 (CHIPS) の標準化はじまる

サードパーティCookieをトラッキングに使用できないようにする「Cookies Having Independent Partitioned State (CHIPS)」という仕組みが議論されています。

現在は、その仕組はW3CのPrivacy CGで議論されています。細かい仕組みは以前書いたとおりです。


( トラッキングに利用できない3rdパーティクッキー「CHIPS」の仕組み (partitioned属性) - ASnoKaze blog )

このCHIPSは、Cookieに新しいPartitioned属性を利用します。Cookie自体の仕様は、IETFが発行するRFC 6265で定義されており、そこにPartitioned属性を追加してやる必要があります。

そのためIETF側にも「Cookies Having Independent Partitioned State specification」というdraftが提出されています。

CHIPSのdraft

Cookies Having Independent Partitioned State specification」のdraftは割りとシンプルです。rfc6265bisで定義されているCookie処理の手順にPartitioned属性周りの処理を追加するだけです。

ユーザエージェントがcookieの保存時
  • set-cookieヘッダを受け取った際に、Secure属性 (secure-only-flagがon) があり、Partitioned属性を処理する
  • 保存時のcookieの"cookie-partition-key"として、ドキュメントの最上位のブラウジング コンテキストのsiteに設定する
ユーザエージェントがcookieを送信するとき
  • cookie-partition-key が設定されている場合は、cookie-partition-keyが一致する場合のHTTPリクエストにcookieを添付する

UUIDv6~UUIDv8と uuidrev の動向

UUIDの新しいフォーマットとしてversion6~version8を追加する提案がIETFで行われていることは、以前記事で取り上げたとおりです。
asnokaze.hatenablog.com

その後、IETFでRevise UUID WGが立ち上がるなど、標準化に向けて動きがあったので簡単に紹介する
(今回は、具体的なUUIDv6~UUIDv8 の紹介は割愛する)

uuidrev

今年の8月、Revise UUID WG (uuidrev) が立ち上がりました。このWGの主な作業領域は次のとおりです。

  • UUIDを定義した RFC4122 を改訂し、既存のエラッタを治す
  • 改訂版仕様にUUIDv6~UUIDv8 を組み込む

なお、これらの作業のマイルストーンとして2023年3月にIESGに提出することが掲げられています。

WG設立の流れは、7月に行われたIETF114の議事録に議論の様子が残っています(議事録URL)。Dispatch WGのミーティングで新しいUUIDの発表があり、この提案仕様の標準化の進め方を議論していました。そこでは、この取組をおこなうためのWG設立が好ましい旨発言されています。

rfc4122bis

uuidrev WGの取り組みとして RFC4122の改訂版となる「rfc4122bis」のdraftが公開されました。

内容は

  • UUIDの基本フォーマット
  • version1~version8までの定義
  • UUIDのベストプラクティス
    • タイムスタンプの精度
    • 分散システムでの生成
    • ソート
    • 衝突性
    • などなど

目次としても、UUIDv6~UUIDv8の仕様が組み込まれたことが伺えます

詳しいエラッタ修正内容はdraft内に説明せれてるのでそちらをご参照ください。

なんにせよ、今後はこのdraftの動向をウォッチしておけば良さそうです。

クエリパラメータ付きURLのキャッシュを改善する No-Vary-Search ヘッダ

キャッシュのキーとしてURLが使われます。このときURLのクエリパラメータも含めて考慮されます。

特定のクエリパラメータは、分析や別様とでアクセスログに残すために使われたりしますが、提供するリソースが変わらない場合があります。そのケースであれば、クエリパラメータが付いてたとしても、キャッシュがあればキャッシュを使ってもらいたいものです (ここでキャッシュは、HTTPキャッシュ及び、prefetchやprerenderを指します)。

そのため、クエリパラメータが付いている場合の扱いを改善する No-Vary-Search レスポンスヘッダ が、Chromeの方中心に議論されています。

github.com

No-Vary-Search レスポンスヘッダの例として次のものが上げられている

クエリパラメータのキーの順序を考慮しない

No-Vary-Search: key-order

特定のクエリパラメータをキャッシュのキーとして考慮しない (特に分析用のものなど)

No-Vary-Search: "utm_source", "utm_medium", "utm_campaign"

特定のクエリパラメータ意外をキャッシュのキーとして考慮しない

No-Vary-Search: *; except=("productId")

HTTPのProxyを改善する「Upgrade: connect-tcp」 の提案仕様

Modernizing HTTP Forward Proxy Functionality」という仕様がIETFに提出されています。

これは、CONNECTメソッドを使った今までのForward Proxyの機能を、新しい(モダン)なしくみに置き換える提案です。HTTP/2やHTTP/3上でHTTP以外のデータをやり取りする場合は、拡張CONNECTの仕組みを使うのが一般的です。例えば、HTTPを介してUDPパケットをProxyするCONNECT-UDPなどもこの拡張CONNECTを使っています。

この拡張CONNECTのアイディアをもとに、今までのCONNECTにバックポートするというのが今回の「Modernizing HTTP Forward Proxy Functionality」になります (参考: MLでの著者のメール)

拡張CONNECT

拡張CONNECTの仕組みは以前説明したとおりです
asnokaze.hatenablog.com

今までのCONNECTメソッド問題点

今までのCONNECTメソッドの使い方は次のとおりです

クライアントはProxyに対してCONNECTメソッドを行い、TCP通信のデータをTargetにForwardしてもらいます

CONNECT server.example.com:80 HTTP/1.1
Host: server.example.com

この方法では

  • Proxyサーバは単一のエンドポイントしか提供できない。VirtualHostや、Pathを使ってサービスを分ける事ができない。
  • クライアントはIPアドレスでTargetを指定する際に、IPv4IPv6どちらで指定すれば良いかわからない

Modernizing HTTP Forward Proxy Functionality

本提案では、拡張CONNECT同様、ProxyのエンドポイントとしてPathを指定できるようになっています。
また、targetとしてIPv4IPv6を併記し、Proxyが選択できるようになっています。

HTTP/1.1

HTTP/1.1ではProxyに対して次のリクエストを送って、targetにデータをforwardしてもらいます

GET /proxy?target_host=192.0.2.1,2001:db8::1&tcp_port=443 HTTP/1.1
Host: example.com
Connection: Upgrade
Upgrade: connect-tcp
  • GETのクエリパラメータとしてtarget_host, tcp_port を指定する
  • ConnectionヘッダにUpgrade を指定する
  • Upgradeヘッダに connect-tcp を指定する
HTTP/2, HTTP/3の場合

HTTP/1.1では拡張CONNECTと同様にリクエストします

CONNECT HTTP/2.0
:authority = request-proxy.example
:scheme = https
:path = /proxy?target_host=192.0.2.1,2001:db8::1&port=443
:protocol = connect-tcp
  • CONNECTで、クエリパラメータとしてtarget_host, tcp_port を指定する
  • protocol疑似ヘッダで connect-tcp を指定する

Webサイトを離れたときにデータを送る Page Unload Beacon (Pending Beacon API)

Webサイトを離れたときにサーバにデータを送れるようにする「Page Unload Beacon」という仕組みが、W3CのWICGで議論されています。

既存のページのライフサイクル(unloadイベントやbeforeunload)で、サーバにデータを送ろうとしても処理されないことがあります。そのため、ページのunload時にビーコンを送るように登録できるようにするのが「Page Unload Beacon」です。

最新のChrome Canaryでとりあえず動くっぽいので、触ってみる (まだ動作するだけで、一部仕様と異なります)

Page Unload Beacon

デベロッパーツールから次の通り実行して、Beaconを登録しておきます。今回はGETリクエストとPOSTリクエストのビーコンをそれぞれ登録。

getbeacon = new PendingGetBeacon("http://example.com/?get");
postbeacon = new PendingPostBeacon("http://example.com/?post");
postbeacon.setData("post data")

その後、Webページを閉じます。

WiresharkでHTTPリクエストを引っ掛けると、次の通りリクエストが飛んでる事ができます

おまけ

  • 通常のBeacon APIと同じようにCookieは付くようです (まだ付かない?)
  • 通常のBeacon APIと同じであれば、「Private Network Access」の制約を受けそう (まだ制約されない?)
  • ネットワークが切断されて切り替わった場合は、ビーコンは送られないぽい (未確認)

ここらへんは実装が進む中で変わりそう