Twitchの動画配信プロトコルWarpのデモを動かしてみる

TwitchはWebTransport over HTTP/3 で単方向のライブストリーミングを可能にするWarpというプロトコル開発してます。
古い記事ですが、以前紹介した通りで、現在IETFで議論が進められています。
asnokaze.hatenablog.com

その Warpのデモコードが公開されたので動かすところまでやる。
github.com

とはいえ書いてある通りやるだけ。僕は、サーバとブラウザを別環境で動かす都合でちょっと弄っている。先に結果だけ書くと

結果

ブラウザで動画が流れる事を確認しました

また、serverを改造してkeylogfileを出力させ、パケットを復号させると

  • SETTINGSフレームで次の値を投げている
    • SETTINGS_WEBTRANS_DRAFT00 = 0x2b603742,
    • SETTINGS_H3_DATAGRAM_DRAFT04 = 0xffd277,
  • サーバからの単方向ストリーム (WebTransport stream=0x54)でデータを転送していることがわかります
    • データの最初にwarp用のjsonが格納されてます

( パケロス時に再送不要なDATAGRAMフレームも仕様上使えるが、まだ使ってなさそう

以下は手順

前準備

今回はUbuntuで動かしたが、ffmpegやnodejsはaptで降ってくるバージョンだと動かないので適宜新しいものを入れる (ffmpegはsnapでいれて、nodejsはv16を入れた)

コードの取得

$ git clone https://github.com/kixelated/warp-demo.git
$ cd ./warp-demo

流す動画ファイルの取得、変換

$ wget http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4 -O media/combined.mp4
$ ffmpeg -i media/combined.mp4 -f dash -use_timeline 0 -r:v 24 -g:v 48 -keyint_min:v 48 -sc_threshold:v 0 -tune zerolatency -streaming 1 -ldash 1 -seg_duration 2 -frag_duration 0.01 -frag_type duration media/fragmented.mpd

証明書の準備

$ ./cert/generate
$ ./cert/fingerprint
sB8TJSHn195H3GJm/6WoibD/OGN5M+w4x7a7RpirLo4=

フィンガープリントは後で使う

/ect/hostsの設定

echo '127.0.0.1 localhost.warp.demo' | sudo tee -a /etc/hosts

サーバの起動

Webサーバ、https://localhost.warp.demo:4444/ で動作する。アクセスすると動画プレーヤーが表示される
( 127.0.0.1でLISTENするので、外からアクセスする場合は ./player/package.json で起動を 0.0.0.0 に指定すれば良い

$ cd player
$ yarn install
$ yarn serve

warpサーバ、https://localhost.warp.demo:4443/ で動作する

$ cd server
$ go run ./warp-server

Chromeでアクセスする

先述の通り、warpサーバを起動したとは別のPCからアクセスするので
localhost.warp.demo を該当サーバのIPに向ける必要がある。/etc/hostsで指定してやれば良い

なお、現状はChrome Canaryを使う必要がある。
で、Chromeを起動時に次のオプションを渡す (起動コマンドは chrome://version で確認できる)

--origin-to-force-quic-on="localhost.warp.demo:4443" --ignore-certificate-errors-spki-list="sB8TJSHn195H3GJm/6WoibD/OGN5M+w4x7a7RpirLo4=" https://localhost.warp.demo:4444

https://localhost.warp.demo:4444/にアクセスする

HTTPのやり取りの最中に付帯情報を送れるMETADATAフレーム

METADATA frame for HTTP/2 and HTTP/3」という提案仕様がIETFに提出されている。

これは、HTTPリクエストやレスポンスをやるとりする際に、HTTPメッセージ(ヘッダやコンテンツ)とは別に追加情報を送れるようにします。追加の情報を送るのに、HTTP/2及びHTTP/3の拡張フレームとしてMETADATAフレームを定義します。METADATAフレームはストリーム上で任意のタイミングで送れるため、HTTPリクエストを送受信してる途中, HTTPレスポンスを送受信してる途中に何度も送信できます。

追加の情報の例としては、「CPUコスト」「負荷分散情報」「統計情報」などを送ることが述べられています。他にも、デバッグ情報など送るのに良さそうだなと思います。これらはHTTPセマンティクスではないので、ヘッダとして解釈されるとかはないです。

この機能はenvoyに組み込まれているしくみで、他にもGoogle QUCHEなどすでに実装しています。(具体的にどう使うのか知ってる方が居たら教えてください...)
github.com

HTTP/2の場合

SETTINGSパラーメタのSETTINGS_ENABLE_METADATAを有効にした場合に使えます。

HTTP/2ではメタデータを付加したいHTTPメッセージのストリームIDを指定します。また、メタデータはキーバリュー形式のデータであり、HPACKのフォーマットで格納します。


HTTP/3の場合

SETTINGSパラーメタのSETTINGS_ENABLE_METADATAを有効にした場合に使えます。

HTTP/3ではメタデータを付加したいHTTPメッセージと同じQUICストリーム上で送信します。また、メタデータはキーバリュー形式のデータであり、QPACKのフォーマットで格納します。

HTTP/3のCONNECT-UDPを利用したWebRTC通信

Proxying Listener UDP in HTTP」という提案仕様がIETFに提出されている。

これは、HTTP/3のCONNECT-UDPを介してWebRTC通信を可能にするための提案である。まだ議論の呼び水と鳴るdraftであるため、ここから仕様は大きく変わると思うが、ざっと眺めていく。

HTTP/3のCONNECT-UDP

本論に入る前に、まずCONNECT-UDPについて説明します。

IETFではすでに「Proxying UDP in HTTP」という仕様が議論されている。これが通称CONNECT-UDPと呼ばれているものである。実は、AppleのPrivate Relayでもすでに使用されているものである。

これは、Proxyと確立したHTTP/3コネクションをトンネリングしてUDPパケットを中継させる機能です。

この通信は第三者からはただのHTTP/3通信としてか観測できないという特徴があります。確立した通信路を通して自由なUDPパケットを中継させることが出来ます。

このCONNECT-UDPでは、H3-Datagramという仕様でUDPパケットを扱います。詳しくは以前書いた記事を参照ください。
asnokaze.hatenablog.com

Proxying Listener UDP in HTTP

通常のCONNECT-UDPではProxyを中継して通信する相手は1つでしたが、WebRTCはSTUNと通信した上で、通信相手のブラウザからもパケットを受け付ける必要があります。そこで、既存のCONNECT-UDP拡張機能として「Proxying Listener UDP in HTTP」が登場しました。

(提案者はユースケースとしてWebRTCをあげていますが、それに限定されるものでは有りません)

主な通信の流れ

上記の図に沿って通信の流れを説明します。

CONNECTリクエストとレスポンス

まずは、ブラウザAと中継サーバとでHTTP/3のコネクションを確立したのち、中継の要望を出す。

通常のCONNECT-UDPのように、拡張CONNECTメソッドを用いる(:protocolにconnect-udpが指定される)。

connect-udp-listenヘッダを付けることで、Proxying Listener UDP in HTTP の通信であることを明示する。ヘッダの値は使用するH3-DatagramのContext-IDを指定する。

HEADERS
  :method = CONNECT
  :protocol = connect-udp
  :scheme = https
  :path = /.well-known/masque/udp/*/*/
  :authority = proxy.example.org
  connect-udp-listen = 2
  capsule-protocol = ?1
|<<

中継サーバは、200番のレスポンスを返し、CONNECTリクエストの受け入れる意志を示す。

>||
HEADERS
  :status = 200
  capsule-protocol = ?1
STUNサーバへのUDPパケットの中継

ブラウザA側は、H3-DatagramUDPパケットを中継サーバに送信する。このとき、中継先となるターゲットのIPとポートを付加して送る。

 DATAGRAM
   Quarter Stream ID = 11
   Context ID = 2
   IP Version = 4
   IP Address = 192.0.2.42
   UDP Port = 1234
   UDP Payload = Encapsulated UDP Payload

中継サーバは、指定されたIP宛にUDPパケットを中継する。

中継サーバはSTUNサーバから応答となるUDPパケットを受け取ると、ブラウザA側に中継する。このときもH3-DatagramでUDPパケットを中継することになる。

このときのH3-Datagramでは、どこからきたUDPパケットなのかが付加されている。

DATAGRAM
  Quarter Stream ID = 11
  Context ID = 2
  IP Version = 4
  IP Address = 192.0.2.42
  UDP Port = 1234
  UDP Payload = Encapsulated UDP Payload

ブラウザBからのUDPパケットの中継

STUNとのやり取りが終わって、ブラウザAとブラウザBがやりとりを開始します。ブラウザBから送られるUDPパケットも、中継サーバがブラウザAに中継を行います。このときもH3-DatagramでUDPパケットを中継することになる。

DATAGRAM
  Quarter Stream ID = 11
  Context ID = 2
  IP Version = 4
  IP Address = 203.0.113.33
  UDP Port = 4321
  UDP Payload = Encapsulated UDP Payload

一般ユーザに払い出すと危険なサブドメインやメールアドレス

ユーザに対して、そのユーザ名のサブドメインやメールアドレスを払い出すWebサービスがあります。

しかし、特定のサブドメインやメールアドレスは特別な用途で使われているものもあります。そのようなサブドメインやメールアドレスを一般ユーザに払い出してしまうと危険です。

現在、IETFでは仕様上利用用途が決められている、それらのラベルをとりまとめる「Dangerous Labels in DNS and E-mail」というdraftが提出されています。

今回はそれを眺めていきます。

(あくまでIETFの取り組みであり、仕様上定義されているものをとりまとめています。クラウドサービスや特定ベンダーで特別利用しているものは現在含まれていません。)

サブドメイン

ここでとりあげるサブドメインは、利用用途が決まってるため一般ユーザに払い出すべきではありません。(例: mta-sts.example.com)

(なお、_example のように、アンダースコアで始まるものはRFC 8552ですでにまとめられています。ここでは紹介はしません。)

  • mta-sts: RFC8461で定義される、SMTP MTA Strict Transport Securityポリシーファイルの設置に利用
  • openpgpkey: 「OpenPGP Web Key Directory」でOpenPGP certificateの参照と検証に利用
  • root-key-sentinel-is-ta-(key-tag): RFC8509で、信頼するDNSSECルートキーを示すのに利用
  • root-key-sentinel-not-ta-(key-tag): RFC8509で、信頼しないDNSSECルートキーを示すのに利用
  • www: ブラウザがWebサイトが動作していると想定して利用する

メールアドレス

ここでとりあげる文字列は、利用用途が決まってるため、メールアドレスのローカルパートとして一般ユーザに払い出すべきではありません。(例: webmaster@example.com)
(なお、大文字小文字は区別しません)

  • abuse: RFC2142で、不正利用時の連絡先として指定
  • administrator: 証明書の発行用途で利用 (CA/B Forum)
  • admin: 証明書の発行用途で利用 (CA/B Forum)
  • hostmaster: RFC2142及び、証明書の発行用途で利用 (CA/B Forum)
  • info: 証明書の発行用途で利用 (参考)
  • is: 証明書の発行用途で利用 (参考)
  • it: 証明書の発行用途で利用 (参考)
  • noc: RFC2142で、ネットワークに関する連絡先として指定
  • postmaster: RFC2142及び、証明書の発行用途で利用 (CA/B Forum)
  • root: システムの問い合わせや、証明書の発行に利用?
  • security: RFC2142で、セキュリティ関係の連絡先として指定
  • ssladministrator: 証明書の発行用途で利用(参考)
  • ssladmin: 証明書の発行用途で利用 (参考)
  • sslwebmaster: 証明書の発行用途で利用(参考)
  • sysadmin: 証明書の発行用途で利用(参考)
  • webmaster: Web関連の問い合わせ先及び、証明書の発行用途で利用 (CA/B Forum)
  • www: webmasterのエイリアスとして使用

CA Browser ForumのBaseline Requirementsは、証明書発行に関するガイドラインです。CAやクラウドサービスでも、メールアドレスベースの検証ではこれらに準拠しており、これらのメールアドレスを検証に用いてますね。

おわり

もちろん今回は仕様で利用用途が定義されているものにフォーカスしています。

他にも危険なものとかありそうだけど、まとまってるのかな?

デフォルトでCookieをオリジンに紐づける、ChromeのOrigin-Bound Cookies

Blinkの開発者メーリングリストで「Intent to Prototype: Origin-Bound Cookies」という議論が行われています。

Cookieをより安全にするために、デフォルトでCookieをオリジンに紐づけるようにする提案です。Cookieをset-cookieしたオリジン以外からは、そのCookieにアクセスできないようになります。

詳しい背景や仕組みについては次のページから確認できます。
github.com

かんたんに、Origin-Bound Cookiesの動作をみていきましょう。

オリジンは、スキーム、ホスト名、ポートの組です。それらのうち一つでも異なれば、オリジンが異なることになります。

例えば、次のようになります。

オプトアウト

議論されているOrigin-Bound Cookiesでは、デフォルトの動作を変更します。オリジンを超えてcookieを共有するために、オプトアウトする仕組みが提供されています。

domain属性を付与することで、オプトアウトできます。オプトアウトすることで、異なるホスト名、ポートとcookieを共有することが出来ます。ただし、異なるスキームに共有することは出来ません。

例えば、https://example.comからセットされたcookieでも「Domain=example.com」が設定されていてれば、https://example.com:1234https://sub.example.comにはcookieが送信されます。ただし、スキームが異なるhttp://example.comには共有されません。

Webサイトのバグの報告先を示す contributing.txt

Webサイトのバグを見つけたとしても、その報告先を知る統一的な方法は現状ありません。

たとえば、脆弱性についてはsecurity.txt があります。https://www.facebook.com/security.txt などで使われています。
asnokaze.hatenablog.com

同様の仕組みで、contributing.txt という形式でバグの報告先を示せるようにする仕組みが提案されています。提案仕様は「a simple way to provide informations for contributors」としてIETFに提出されています。

contributing.txtをWebページの最上位階層に配置します (例: https://example.com/contributing.txt )

そのファイルは次の情報を含めることが出来ます。

Admin: Valentin Binotto
Bugs: bugs@vauly.net
Open Source: github.com/valentinbino
License: Creative Commons Attribution 4.0 Int. Public License
Guidelines: github.com/valentinbinotto/v434/guidelines.txt
# Valentin Binotto
# Hello, world!
  • Admin: Webサイトの管理者
  • Bugs: バグレポートを出せるメールアドレスまたはURL
  • Open Source: GithubやGitlabなどより議論するのに適切なURL
  • License: ウェブサイトのコンテンツに適応されるライセンス
  • Guidelines: このWebサイトにコントリビューションするためのガイドラインのURL
  • #~~ : コメント

ChromeのCache Transparencyに関するメモ

Chromeではキャッシュの効率改善を目的とした「Cache Transparency」という仕組みが検討されているようです。

これは、「Double-keyed HTTP cache」によってキャッシュヒット率低下を緩和します

まだまだ実験を行っている段階ですが、簡単にメモとして残しておく

背景: Double-keyed HTTP cache

Double-keyed HTTP cacheは、ユーザのプライバシーを保護するために、HTTPのキャッシュをサイトごとに分離する仕組みです。

簡単な例で見ていきましょう

この時、https://cdn.exampleから読み込んだリソースをキャッシュするわけでが、同一のリソースであったとしてもa.example用とb.example用でキャッシュ領域を分けます。

こうしておかないと、a.example側はアクセスしたユーザがb.exampleにすでにアクセスしたことがあるのか、リソースの読み込み速度から類推することができしていまいます。

この時、キャッシュのキーが 『読み込んだサイト(URLバーに表示されてるURL)』+『読み込んだリソースのURL』と2つのキーになることからDouble-keyed HTTP cacheと呼ばれています。

Chromeの分析では、Double-keyed HTTP cacheによりキャッシュのヒットミスが3%増えたという分析がなされています。

Cache Transparency

Cache Transparencyは、Blink-devメーリングリストの下記のスレッドで議論されています
groups.google.com

主な目的は、Double-keyed HTTP cache導入によって上がったキャッシュのヒットミス率の低減があげられています。

その方法としては、一般に広く利用されているリソースであれば、Single-Keyキャッシュで扱ってもユーザのプライバシーには影響しないという仮説に基づいています。

"一般に広く利用されているリソース" は、Google独自の方法(Chromeのテレメトリ, クローラー)で調査され、Pervasive Payloads listとしてリスト化されます。Pervasive Payloads listには、リソースのURLとペイロードハッシュ値が含まれ、それに一致するリソースはSingle-Keyキャッシュとして保存されます。

まだ事前の効果測定を行う段階で、実験として以下の条件を満たすリソースを対象にすることが議論されていますが。まだFixはしてなさそうです。

  • 少なくとも500のサイトに含まれる
  • 月に少なくとも1,000万回フェッチされたもの

終わりに

Double-keyed HTTP cacheによる、キャッシュミスヒット率の緩和策として出てきたCache Transparency。

まだまだ話が始まったところなのでどうなるかはわからないが、Webサイトのデベロッパーとしては、JSやCSSは共通のCDNをURLからダウンロードしたほうがお得になるかもしれない...

どうなるんだろう