DNSを使ってTLSハンドシェイクを高速化するZTLSについて

ZTLS: A DNS-based Approach to Zero Round Trip Delay in TLS」という論文が公開されている。アイデアが面白いので簡単に眺める。

PDFも今のところACMのサイトから見れる
https://dl.acm.org/doi/abs/10.1145/3543507.3583516

概要

  • DNSからTLSハンドシェイクに必要な情報を通知し、0-RTTハンドシェイクを行う
  • 通常のTLSと互換性がある

シーケンス図


(引用: 「ZTLS: A DNS-based Approach to Zero Round Trip Delay in TLS」 Figure 3)

  • 事前に、サーバ側はZ-Data(ハンドシェイクに必要な情報)をDNSにアップロードしておく
  • クライアントはサーバDNSに対してAレコードと、Z-Dataを含むレコードを並列に問い合わせ取得する
  • クライアントは、取得したZ-Dataに含まれるデータと自身のClientHelloの情報を元にセッションキーを生成する。その鍵でアプリケーションを暗号化し、Encrypted App Dataとして送信する。あわせてztls拡張として使用したZ-Dataのバージョンをサーバに通知する。
  • サーバは受信したClientHelloにztls拡張がなければ通常のTLSハンドシェイクにフォールバックする。ztls拡張があれば、そこに含まれるZ-Dataバージョンを元にクライアントが使ったZ-Dataを手元に用意します。そこからセッションキーを導出し、Encrypted App Dataを復号します。それ以外は、ほぼ通常のTLSと同じようにServerHelloを応答します。(Certificateは省略可能)


Z-Dataには、本Z-Dataのバージョン、本Z-Dataの有効期限、DH グループ、DH public key、証明書が格納されています。

有効性

詳しくは論文に記載のとおりだが、実際にその有効性についても実験を行っている。
アジアの各AWSリージョンにインスタンスを起動し、実際に1-RTT分早くなっている事を確認している。

感想

これって、中間者攻撃に対して初回のEncrypted App Data保護できてるのかな... よく分かってない

HTTP上でL2VPNを実現する Proxying Ethernet in HTTP について

Proxying Ethernet in HTTP』という仕様がGoogleのAlejandro R Sedeño氏から提出されています。これは、HTTP上でイーサネットフレームを送受信させるための仕様です。

背景として、IETFでは、Masque WGにおいてHTTPコネクション上で通信をトンネリングする仕組みの標準化を行っています。

すでに標準化が進められている、上記の仕様に続きイーサネットフレームを取り扱えるようにするというのが今回の提案です。ユースケースについては、L2VPNを実現するのに利用する例が挙げられています。

Proxying Ethernet in HTTPの概要

Proxying Ethernet in HTTP』では、"RFC 9297 HTTP Datagrams "を利用し、HTTP/1.1~HTTP/3でイーサネットフレームをトンネリング出来るようにします。

大まかな通信の流れは、"RFC 9298 Proxying UDP in HTTP" などと同様、拡張CONNECTメソッドでconnect-ethernetネゴシエーションし、HTTP DATAGRAMを利用しデータをトンネリングさせます。

通信例


draftに記載のL2VPN通信路の確立について説明します

  • HTTP/3コネクション確立時に、拡張CONNECT及びHTTP DATAGRAMを利用するためのSETTINGSパラメータを交換しておきます
  • クライアントは拡張CONNECTでconnect-ethernetの利用を要求します
  • Proxyはもしconnect-ethernetの通信を受け入れる場合は200で返します
  • その後は、HTTP DATAGRAMにイーサネットフレームを格納して送受信します。なお、DATAGRAMフレームには拡張CONNECTを使ったストリームと紐づけるためのコンテキストが付与されます

認証関連のリンクを示す『Link relationship types for authentication』

Link relationship types for authentication」という仕様が、IETFのHTTPAPI WGで議論されています。

例を見るのがわかりやすいと思います。

authenticate

aリンクで、リンク先をログインページということを示すことが出来るようになります。コレに対してブラウザは、ログインをナビゲーションするUIを表示したりできるようになります。

<a href="/login" rel="authenticate">Login</a>
authenticated-as

authenticated-as を使うことで、認証されたユーザの情報を取得できるリンクを示します。自身が誰として認証されているかわかります。

これは、特にAPIコールするときに有用です。自身がどの権限でAPI叩いてるかがわかるリンクを取得できるようになります。

下記はレスポンスヘッダで、認証されたユーザのユーザ情報のリンクを通知する例です

Link: <https://api.example.org/users/123-abc>; rel="authenticated-as"
logout

rel="logout" でログアウト用のリンクを示すこと出来ます。

register-user

rel="register-user" ではユーザを登録するリンクを示すことが出来ます。

状況

特にクライアントでの実装例や、サービスでの利用例は具体的には共有されてないです

ChromeのIsolated Web AppsでTCPソケットをリッスンする

以前紹介したように、ブラウザでTCPソケットを扱う『Direct Sockets API』という仕様があります。

asnokaze.hatenablog.com

前回紹介したときから時間はたち、Isolated Web Appsでの利用に限定されたり、TCPサーバソケットをリッスンできるようになったりしている。

Isolated Web Apps

Isolated Web Appsは、Web技術を用いて作られたアプリケーションを独立した環境で動作させる仕組みです。現在、フラグ付きでChromeを起動することで動作させることが出来ます。
github.com

アプリケーションの例として、Telnetクライアントを動作させる Isolated Web Apps が公開されています。
github.com

Webアプリケーションに署名し、サーバを起動させた、フラグ付きで起動したChromeで動作確認できます(詳しくはリポジトリ参照)

Chromeの起動はこんな感じです。

google-chrome-unstable --enable-features=IsolatedWebApps,IsolatedWebAppDevMode \
                       --install-isolated-web-app-from-url=http://localhost:8080

その後、"chrome://apps/" を開くと該当アプリが確認できます。


Direct Sockets API

Direct Sockets APITCPソケットやUDPソケットを操作するAPIを定義しています。現在はIsolated Web Apps環境でのみ動作させることが出来ます。
wicg.github.io

今回、TCPサーバソケットをリッスンできるようになったので軽く動作確認 (現状 reader しか無さそう)。
環境準備は面倒くさいので、上記のIsolated Web Appsを起動しデベロッパーツール経由でスクリプトを実行します。

こんな感じで実行すると、該当ポートでちゃんとリッスンされました。

const socket = new TCPServerSocket("0.0.0.0", {localPort:10083})
const { readable } = await socket.opened;
const reader = readable.getReader();

while (true) {
  debug = await reader.read();
  console.log(debug)
}

(valueがうまく取れなかったけど、、なんかおかしい?)

ひとまず、telnetで適当に文字を打って、wiresharkで見るとちゃんとリッスンしてAckを返せてるところまでは確認できた。

その他

この仕様についてはセキュリティ上の懸念事項は多くあります。何かあれば本家で語られているQ&Aを拝見してください
https://github.com/WICG/direct-sockets/blob/main/docs/explainer.md#security-considerations

IETF116 Yokohamaをもっと楽しむために (その2) ~当日編~

ついに、IETF 116 Yokohamaが始まりましたね!!横浜で僕と握手!!


WGのミーティングは月曜日からですので、ちょうど直前ということになります。
パシフィコ横浜ノース 3Fで受付を済ませたあとは、アジェンダ(URL)のページを参考に会議室に行くだけです。


WGのミーティングでは、前回議論した提案仕様のIssueが議論されます。できれば、WGミーティングのAgendaは抑えて予習はしておいた方が良いかと思います。とはいえ、会議中にちんぷんかんぷんでも情報を追うコツを幾つか書いておこうと思います。

心得

  • 英語は分からない、、、みんな分からない大丈夫!!
  • せっかくなので色々な人に話しかけよう (議論とかは詳しい人に聞こう!)
  • 無理して全部のミーティングに出る必要はない!

WG ミーティング

materials

各WGのアジェンダ及び発表資料は マテリアルページ(URL)に記載されます。スライド等適宜みることをおすすめします。

合わせて前回のIETF115の発表資料や議事録を見ておくのも良いでしょう

draftの段階を知る

WGで話しているdraftがどういう状態かをラフにつかむと議論のスコープがわかります。

  • draftは誰でもだせるため、最初のうちは『それがIETFで取り組むべきことなのか』といった取り組みの是非が議論されます。
  • その後『draftが解決する問題の範囲』とスコープの議論に行われます。
  • 続いてプロトコル設計の議論が行われるようになります
  • ある程度成熟すると、個人提出draftから、WGで標準化のために取り組む事が決まります (WG Draftに昇格)
  • さらにdraftが成熟すると、細かいIssueの議論や、実際にインターネットでデプロイした報告が行われるようになります
  • 最後にRFC発行に向けて、細かいエラーハンドリングや単語の整理など、徐々にテクニカルな議論が収束していきます。

個人draftと、WG draftの見分け方は

  • draft-shade-quic-http2-mapping-00 (draft-の後に個人名が来てるのが個人draft
  • draft-ietf-quic-http (draft-の後にietf, WG名と書かれてるのがWG Draftです

ですので、いまどういうった議論してるかはフェーズによって異なります。

議事録

ボランティアのノートテイカーによって、会議中はリアルタイムに議事録が取られていきます。英語で聞きづらい所は、機械翻訳に掛けると議論が断片的に追えます。

アジェンダ(URL)ページのノートマークからたどることが出来ます。

meetecho

リモート会議システムとしてmeetechoを利用しています。現地参加でも、各WGミーティング中にmeetechoにログインすることをおすすめします。喋ってる人の名前が分かりますし、結構チャットで議論が行われていたりします。

出席確認はmeetechoへのログインにより行われます。IETFでは会議に誰が参加したのか透明性のために明らかにしています。

また、マイクでの発言待ち行列の管理や、投票機能を使う場合もmeetechoが使われます。ミーティングでは必須かとおもいます。

アジェンダ(URL)ページのビデオマークからたどることが出来ます。

ハミング

IETFではWG内でのコンセンサスを元に物事を進めていきます。そのため、会議中に会議室内のコンセンサスを図る機会があります。
それがHum/ハミングと呼ばれる行為です。

議長が「~~に賛成な人 please hum Now.....」「~~に反対な人 please hum Now.....」とHumを呼びかけるので、意図したほうでハミング(Hummmmmmmm~~) とハミングして答えます。

IETFでのコンセンサスを支える大事な仕組みです。

人を知る

議論の最中、喋っている人がどういう人7日しると良いでしょう。IETFでは会社に所属してる一方で個人での参加の色が強いです(Googleの人だからって、Googleとして意見を言ってるわけではない)。所属会社は参考になりますが、気をつけたいところです。

詳しそうに喋ってる人は、RFCの著者だったり、WGチェア、エリアディレクターだったりします。こういった方はキーパーソンで、議論の整理をしてくれたりします。そういうった方の発言に耳を傾けると道標になります。

サイドミーティング

アジェンダページに記載されてないので見落としがちですが、サイドミーティングというものがあります。
IETF 116 Side Meeting Signups | IETF Community Wiki

WGが結成される前に行われる、有志の会議になります。こちらも、会議室に直接いけば参加できます。
資料や議事録が共有されないことも多いので、より現地参加でサイドミーティングにでると良いでしょう

HTTPの通信を辞書で圧縮する提案について

現在 ChromeではHTTPの通信をBrotliの辞書で圧縮する『Feature: Compression dictionary transport with Shared Brotli』という仕組みの開発が進められています。

この仕組は、来週開催されるIETF 116のサイドミーティングでも議論が行われる予定になっています。

なので、軽くその仕組について予習をしておく。仕組みについて説明したドキュメントはこれ
github.com

Compression dictionary transport

基本的なアイデアとしては、サーバからBrotliの辞書データを提供して、以降のHTTP通信では(使える場合は)その辞書を活用してHTTPレスポンスを圧縮する (辞書データは他のサイトとは共有されない。Pathに合わせて複数の辞書を使い分けできるようになっている)

辞書データとしては、大きく2種類のユースケースがある (圧縮/解凍の利用のながれは一緒)

  • 普通にダウンロードしたJSファイルやCSSファイルをそのまま次回以降の辞書データとして活用する (jsやcssの一部変更があった場合に、ダウンロードし直す際に大きな圧縮効果を発揮する)
  • Linkタグで辞書データを指示し、使わせる

辞書データとしての保持

ファイルを取得する際に、取得したリソースを今後辞書データとして保持するまでの流れを説明します。
今回は、example.comのページからstatic.example.comのjsファイルを取得する流れで説明します。


  • クライアントは、このCompression dictionary transportに対応している場合、Accept-Encodingにsbrを追加してリクエストを送ります
  • サーバは
    • bikeshed-use-as-dictionaryとしてこの辞書を適応するPathの範囲を通知します (ヘッダ名は仮置きとなっている)
    • このやり取りではCORSが必須になるため、Access-Control-Allow-Originを付けます
    • Varyでこのキャッシュキーとして辞書データが依存することを通知する
  • クライアントは、レスポンスを受け取ったらこのデータを辞書データとして保持する

Linkタグで辞書データを読み込むときも概ね同じ流れになります。

辞書データの活用

次に、先の例で保持した辞書データを活用する流れを説明します。

  • クライアントは、辞書データを適応するPathに適合するリクエストを送る際、辞書を持っていることをsec-bikeshed-available-dictionaryヘッダで通知します。
  • サーバは、クライアントが持つ辞書を使って圧縮できる場合は圧縮します。このときヘッダに「Content-Encoding: sbr」が付きます (該当の辞書データがない場合は普通に圧縮する)。

圧縮効果やセキュリティなど

圧縮効果についてリサーチが進められています。
https://github.com/yoavweiss/compression-dictionary-transport/blob/main/examples.md
各サイトのJSファイルなどが大きく圧縮できる事がシミュレートされています。

また、セキュリティについてもCRIMEやBREACHといった圧縮効率から機密データを推測する攻撃が頭をよぎります。そのため、ユーザ固有の機密データが辞書データに含まれないようにしなければなりません。
https://github.com/yoavweiss/compression-dictionary-transport#risks

キャッシュを補助する HTTP Availability Hints の仕様

HTTP Availability Hints」という提案仕様がMark Nottinghamによって提出されています。

この提案仕様では、キャッシュで使用されるVaryを補助します。この情報により、キャッシュサーバは効率が向上します。

背景

例えば


  1. Client 1から英語(en)のコンテンツが要求され、CDNは英語コンテンツをキャッシュする
  2. Client 2から日本語(ja)のコンテンツが要求される

CDNがOriginからレスポンスを受け取った際に、"vary: Accept-Encoding" がついています。そのため、CDNはオリジンのコンテンツがaccept-languageに依存していると判断して、日本語(ja)の要求をOriginにプロキシします。

このとき、Originが日本語(ja)には対応しておらず結局英語(en)のコンテンツが返ってくることもあります。CDNは英語(en)のキャッシュが会ったため、無駄なやり取りをしてしまったことになります。

このケースにおいては、Originがjaのコンテンツを提供できないことをCDNが知っていれば、キャッシュしている英語(en)をClient2に返すことができます。

HTTP Availability Hints

HTTP Availability Hints」では、Varyで指定されたヘッダのうちオリジンが提供可能な種類を示せるようにします

Vary: Accept-Encoding, Accept-Language, ECT
Avail-Encoding: gzip, br
Avail-Language: fr, en;d
Avail-ECT: (slow-2g 2g 3g), (4g);d

Avail-Languageでは、フランス語(fr), 英語(en)が提供であることを示しています。デフォルトとして英語(en)が指定されているので、日本語のコンテンツが来たとしても英語のコンテンツを返していいことがわかります。

現在の提案仕様では、例として次の補足情報が定義されています。

Avail-Encoding
Vary: Accept-Encoding
Avail-Encoding: gzip, br
Avail-Format
Vary: Accept
Avail-Format: image/png, image/gif;d
Avail-Language
Vary: Accept-Language
Avail-Language: en-uk, en-us;d, fr, de

Cookieでは依存するクッキー名を指定できます

Vary: Cookie
Cookie-Indices: id, sid