WiresharkがHTTP/3に対応した

本日、Wiresharkが「Development Release (3.3.0)」を公開しました。

このバージョン3.3.0ではHTTP/3のサポートが入っています。ダウンロードして早速試していきましょう。

結果

HTTP/3レイヤの単方向ストリームタイプや、フレームタイプが確認できます
(QUICを復号する必要はあります)
f:id:ASnoKaze:20200916122345p:plain

もちろん、「http3」というフィルタも使用できます。

ただ、まだ開発途中であり、基本的な部分しか実装されておりません。そのため、まだパースされない部分もたくさんありますが、今後の開発に期待です。

補足

  • 今回はFirefox Nightly と google.com の通信をキャプチャしました
  • 現時点でWiresharkがサポートしているのはQUIC(draft-21~draft-30), HTTP/3(draft-29), QPACK(draft-16)になります
  • HTTP/3はQUICにより暗号化されているので、復号するために環境変数にSSLKEYLOGFILEを設定しました。復号方法は下記を参照

asnokaze.hatenablog.com

おまけ

こちらもよければ
asnokaze.hatenablog.com

DNSのエラー理由を通知するExtended DNS Errorsの仕様

DNSでは、DNSSECでの不整合や、ポリシーによってブロックされて問い合わせがエラーとなることがあります。

Google Chromeでは「Extended DNS Errors(EDE)」という仕様のサポートが検討されています。これは、問い合わせに対するエラー原因を通知するための仕様で、EDNS0のオプション領域にエラーコードとエラー文を含めて応答できるようにするものです。現在IETFで標準化中になります。

これによってDNSのエラー原因がわかりやすくデバッグが用になるほか、ユーザへのエラー画面を出す際により分かりやすい文言を出せるようになります。

Chromeでの実装検討の詳細については下記の資料を参照ください。
https://docs.google.com/document/d/1PItRbCJHgv1CcqjnkOw1F8oup3oISkMf_xxKZmqGhiU/edit#heading=h.7nki9mck5t64

ここでは、Extended DNS Errorsを簡単に紹介します

Extended DNS Error EDNS0 option

EDNS0のOPTIONとして、定義されています。

f:id:ASnoKaze:20200910000926p:plain

  • OPTION-CODE: EDNS0としてのオプション番号
  • OPTION-LENGTH: オプションの長さ
  • OPTION-CODE: エラー番号
  • EXTRA-TEXT: エラー内容を示す文字列

このオプションがレスポンスに追加されて返されます。

定義済みエラー

下記のエラーコードが仕様で定義されています。ざっと、雰囲気がわかるかと思いますが、エラーコードの詳細については仕様(URL)を参照ください。

  • 0 Other
  • 1 Unsupported DNSKEY Algorithm
  • 2 Unsupported DS Digest Type
  • 3 Stale Answer
  • 4 Forged Answer
  • 5 DNSSEC Indeterminate
  • 6 DNSSEC Bogus
  • 7 Signature Expired
  • 8 Signature Not Yet Valid
  • 9 DNSKEY Missing
  • 10 RRSIGs Missing
  • 11 No Zone Key Bit Set
  • 12 NSEC Missing
  • 13 Cached Error
  • 14 Not Ready
  • 15 Blocked
  • 16 Censored
  • 17 Filtered
  • 18 Prohibited
  • 19 Stale NXDOMAIN Answer
  • 20 Not Authoritative
  • 21 Not Supported
  • 22 No Reachable Authority
  • 23 Network Error
  • 24 Invalid Data

HTTP/2の仕様、改定作業が始まる

もくじ

HTTP/2の改定作業

HTTP/2の仕様は2015年に「RFC7540 Hypertext Transfer Protocol Version 2 (HTTP/2)」として標準化されています。

RFCは公開されたあとに、エラッタが見つかることがあります。このようなエラッタを修正するために、新しくRFCを出し直すということが行われます。

HTTP/2においてもいくつかのエラッタが公開されています (参考リンク)。そのため、それらを修正するためのたたき台として、MozillaのMartin Thomson氏によって改訂版の草案となる「http2bis」が提出されています。

Martin Thomson氏のたたき台は用語の修正とエラッタの修正のみが含まれていますが、IETF HTTP WGのメーリングリストでこの改定作業に含める修正ポイントについて議論が行われています(参照: Time to refresh HTTP/2?)

その議論になっている修正ポイントについて目を通していきます

(これらは議論中であることに注意してください。改訂版に必ず含まれるわけではありません。)

修正点

優先度制御について

HTTP/3の標準化の中で、HTTPにおける優先度制御について見直しがされています。そのため、HTTP/2におけるweightとdependencyを用いた優先制御をHTTP/2の仕様に残すかという議論が出ています。

もちろん、相互運用上問題にならないようにフレームのフィールド定義などは変更しないでしょうが、仕様としてどのような言及になるかは気になるところです。

新しい優先制御方式については以前書いたとおりです。
asnokaze.hatenablog.com

TLS1.3および0-RTT

HTTP/2の仕様はTLS1.3より以前に標準化されています。そのため、それらについて言及されていません。

同様に0-RTTについても言及がありません。0-RTT時のサーバSETINGSといったトピックや、RFC8470などへの言及が考えられます。

GREASEのコードポイントの予約

GREASEの予約について。GREASEは以前書いたとおり
asnokaze.hatenablog.com

疑似ヘッダの扱い

定義されていない疑似ヘッダの使用は禁止されていましたが、RFC 8441 WebSockets over HTTP2では :protocol という疑似ヘッダを追加しています。

あとから出たRFCで追加定義を行うことは、仕様上問題ではありませんが、新しく :protocolの使用を許可するか、禁止というのを緩和するかの判断余地があります。

RFC 8441は以前書いた通り
asnokaze.hatenablog.com

h2cの削除

2020/09/10 修正
TLSを利用しない平文のHTTP/2を削除

http/1.1からのupgradeメカニズムの議論
github.com


セマンティクス仕様への参照

HTTP/2の頃は、HTTPのセマンティクスとしてHTTP/1.1の仕様であるRFC 7231を参照していました。

現在、IETF HTTP WGでは、HTTP/1.1の仕様からHTTPのセマンティクスと、HTTP/1.1のフォーマットの仕様を分離し下記のように整理する作業を行っています。

HTTP/3のdraftではすでにHTTPのセマンティクス定義として上記を参照するような形になっていますが、HTTP/2の改訂版ではどうするか議論の余地があります。

そのた参照の更新

HTML5の仕様として下記をさんしょうしているので更新する

security considerations の追記

RFC発行後に見つかった実装上の脆弱性について、追記を行う。
例えば、CVE-2019-9511 ~ CVE-2019-9518 など

参考: https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md

認証付き暗号の鍵利用上限について

認証付き暗号 "Authenticated Encryption with Associated Data (AEAD)" の利用上の制限について、「Usage Limits on AEAD Algorithms」というドキュメントが公開されている。

このドキュメントでは機密性と完全性を一定以上に保つために、一つの鍵の利用上限についてまとめています。

RFC 8446 TLS1.3」を読んだことがあれば、その仕様の中で「5.5. Limits on Key Usage」の章で、一つの鍵でAES-GCMでレコードを暗号化していい上限値を規定しているのをご存知かもしれません。また、同様の記述がQUICの仕様(URL)にも記述されています。(上限に達する前に鍵更新が行われます)


このように暗号の解析についてはいくつかの論文に分散しているため、プロトコルの標準化を行うために各仕様から参照できるように一つのドキュメントとしてまとめようということになっています。

ドキュメントは鍵について、2者間での利用ケースについて説明したSingle-User AEAD Limitsと、複数ユーザでの利用ケースについてMulti-User AEAD Limitsを説明しています。

ここでは、Single-User AEAD Limitsの上限について紹介します

前提

以下の変数を導入します

  • n: ブロックごとのbit数
  • k: AEAD鍵のbit数
  • t: 認証タグのbit数
  • l: 各メッセージのブロック数
  • s: 全てのメッセージの平文のブロック数
  • q: ユーザの暗号化の試行回数
  • v: 攻撃者の偽造試行回数
  • p: 攻撃者の攻撃確率

また、機密性及び完全性の特性を破る確率の増加率を優位性として定義します。

  • Confidentiality advantage (CA)
  • Integrity advantage (IA)

TLS1.3ではCAを2^(-60)、IAを2^(-57)になるように制限しています。

AEAD_AES_128_GCM、AEAD_AES_256_GCM

AEAD_AES_128_GCM、AEAD_AES_256_GCMにおける上限について紹介する

CAを下記に抑えるために

   CA <= ((s + q + 1)^2) / 2^129

ある仮定のもと、暗号化の上限回数は下記となる

   q <= (p^(1/2) * 2^(129/2) - 1) / (l + 1)

IAを下記に抑えるために

   IA <= 2 * (v * (l + 1)) / 2^128

下記の上限回数となる

   v <= (p * 2^127) / (l + 1)

その他

紹介しないが、同様に次の暗号アルゴリズムの上限回数がドキュメントでは紹介されている

  • AEAD_CHACHA20_POLY1305
  • AEAD_AES_128_CCM
  • AEAD_AES_128_CCM_8

ブラウザからTCP, UDPソケットを操作するDirect Sockets API

(2020/09/17 注釈: Raw SocketsからDirect Socketsに名称が変更されました)


ブラウザでTCP, DUPソケットを操作可能にする「Direct Sockets API」という仕様がW3CのWICGで議論されている。

f:id:ASnoKaze:20200830232335p:plain

また、blink-devでも「Intent to Prototype: Raw Sockets API」とプロトタイプの議論が行われている。

多くの方がセキュリティ上の懸念を抱くと思うが、ドキュメントでも慎重に検討すると書かれている。GithubでIssueを立てることも可能なので、思うことがある方は、まだまだ議論は始まったばかりでもあるので是非フィードバックされると良いと思う。(割と普通に聞いてもらえます)

なお、Raw Socketsという名称については変更も提案されているため、今後変更される可能性がある。

ユースケース

既存のプロトコルを話せるWebアプリケーションの作成が大きなユースケースである。例えば、SSHや, RDP, IRCなどが挙げられている。

API

今後、多くの変更

TCP

下記のように、リモートアドレスとポートを指定してTCP接続を開始する

const options = {
    remoteAddress: 'example.com',
    remotePort: 7,
    keepAlive: false,
    noDelay: false
};
navigator.openTCPSocket(options).then(tcpSocket => { ... }).else(error => { ... });

その後、readableStream, writableStreamで送受信を行う

UDP

UDPの場合は下記の通り

const options = {
    remoteAddress: 'example.com',
    remotePort: 7
};

try {
  const udpSocket = await navigator.openUDPSocket(options);
  doStuffWith(udpSocket);
  ...
} catch (err) {
  // handle error
} finally {
  udpSocket.close();
}

blobをsendする形でデー送信を行う。

let blob = ...;
await udpSocket.send(blob);

セキュリティ関連

まだまだ、多くのことを議論しなければならないし、対策方法についても議論の余地があると思うが、現在議論されている驚異は以下のとおりです。

  • MITM
  • ユーザの合意のない通信の開始
  • DDoS
  • CORSポリシーの回避
  • iframeによる利用
  • プライベートアドレス(内部ネットワーク)への接続

各脅威に対する対策方針の詳細はドキュメントを参照のこと

最後に

まだまだこれからだし、セキュリティ的には色々考慮事項が多いので注視していきたい

HTTP Client Hint Reliabilityの提案仕様

GoogleのDavid Benjamin氏から「Client Hint Reliability」という提案仕様が出されている。なおW3C WICG側でも議論行われている (URL)

まず、Client Hintについて説明してから、Client Hint Reliabilityの説明を行う。

HTTP Client Hint

HTTP Client Hint」という仕組みが、広く使われるようになっています。

HTTP Client Hintは、Webページを表示するにあたりヒントをクライアントからサーバに送ります。例えば、 DPR 解像度 をCH-DPRリクエストヘッダに付加して送信したりできます。

その他に、最近で言えばChromeがUserAgentヘッダの情報量を少なくし、代わりにより詳細なユーザエージェント情報を要求するのにHTTP Client Hintが利用されています。
asnokaze.hatenablog.com

このHTTP Client Hintでは、Accept-CHレスポンスヘッダでサーバがほしいと思うClient Hintのみを要求することで、不用意なクライアント情報の送信を抑制することが出来ます。

User Agent Client Hints の流れを簡単に以下に示す
f:id:ASnoKaze:20200722014902p:plain

  • クライアントはサーバにリクエストを送る
  • サーバは追加のUA情報としてUA-Archを要求する
  • クライアントは UA-Arch をサーバに送信する

Client Hint Reliability

上記で説明したように、Client Hintの仕組みでは、最初のリクエストにはサーバが必要とする情報がついてない場合があります。この問題に対応するのが「Client Hint Reliability」です。

Client Hint Reliability」では、下記の独立した2つのアプローチを提案している。

  • Critical-CH: 必要な情報をつけて送り直してもらう
  • ACCEPT_CH: 事前に、必要な情報を通知する
Critical-CH

新しくCritical-CHレスポンスヘッダを定義します。

Critical-CHヘッダは、必要なClient Hintsが無いのでリトライするようにクライアントに指示することができます。

例えば、下記のように使用する

     HTTP/1.1 200 OK
     Content-Type: text/html
     Accept-CH: Sec-CH-Example, Sec-CH-Example-2
     Vary: Sec-CH-Example
     Critical-CH: Sec-CH-Example

サーバは受け取ったリクエストヘッダにsec-ch-exampleがなかった場合、Critical-CH: Sec-CH-Exampleを含むレスポンスを返して、クライアントにこのClient Hintsを付加してリクエストをリトライするよう伝えることが出来ます。

ACCEPT_CH拡張フレーム

Critical-CHでは1RTT分のやり取りが発生してしまいました。それを回避する方法が、HTTP/2拡張フレームとして新しく定義するACCEPT_CHフレームを使う方法です。

フレーム定義は下記のとおりです。
f:id:ASnoKaze:20200722020506p:plain

内容は下記のとおりです

  • 適応するオリジン (HTTP/2では複数ドメインのリクエスト/レスポンスが多重化されるため)
  • Accept-CHの値

これは、Accept-CHヘッダ相当の情報を拡張フレームに詰めて送信できるということです。拡張フレームにすることで何が嬉しいかというと、クライアントからのリクエストを待たずしてAccept-CHヘッダ相当の情報を送信可能になる点です。

TLS1.3ではハンドシェイク後にサーバの方が先にHTTP/2のフレームを送信できます。また、TLS ALPSを利用することで、TLSハンドシェイク中にAccept-CH情報をクライアントに渡す方法も検討されています。

TLS ALPSを使うことで、最初のHTTPリクエストでサーバが必要なClient Hintsを付けることが出来るようになります。
f:id:ASnoKaze:20200722110301p:plain

TLS ALPSの紹介は下記を参照
asnokaze.hatenablog.com

HTTPSの接続情報を通知する "HTTPS DNSレコード" の提案仕様

HTTPSで通信を開始する際に、事前に知っていると有用な情報が幾つかあります。

  • サーバがHTTP/3に対応しているか(Alt-Svc情報)
  • TLS Encrypted Client Hello で必要な情報
  • サーバがHSTSを要求してくるか

このような情報を提供する新しいDNSレコードを定義する仕様が提案されています。提案仕様「Service binding and parameter specification via the DNS (DNS SVCB and HTTPS RRs)」では、サービスに関する情報を通知する一般形式であるSVCBレコードと、HTTPS用であるHTTPSレコードを定義しています。

もともとはHTTPSSVCレコードという名称でしたが、最近改称されHTTPSレコードになりました。

また、このHTTPSレコードを用いることでANAMEレコードが解決しようとしていた、APEXを別のレコードに飛ばすことも可能です。

簡単に紹介していきます。

実装状況

Chromeがすでに実装を開始しています

また、CloudFlareではすでに、このHTTPSレコードを返すようになっています (レコードタイプ 65)。下記はうまくデコード出来てませんが、HTTP3のドラフト版対応を通知してます。

$ dig  blog.cloudflare.com type65 +short
;; ANSWER SECTION:
blog.cloudflare.com.    294     IN      TYPE65  \# 76 000100000100150568332D32390568332D32380568332D3237026832 0004000868121A2E68121B2E00060020260647000000000000000000 68121A2E26064700000000000000000068121B2E

概略

HTTPSは下記のような形式をしています。

Name TTL IN HTTPS SvcPriority TargetName SvcParams

具体例を見ていきましょう

   pool  7200 IN HTTPS 1 h3pool alpn=h2,h3 port="443" echconfig="123..."
                 HTTPS 2 .      alpn=h2 echconfig="abc..."

   pool   300 IN A        192.0.2.2
                 AAAA     2001:db8::2
   h3pool 300 IN A        192.0.2.3
                 AAAA     2001:db8::3

HTTPSレコードの中身の最初の値は優先度で、異なる優先度でHTTP/3用とHTTP/2用のレコードがあります。

1つ目のHTTPSレコードは、TargetNameとしてh3poolという指定してきます。このe3poolのエンドポイントが、poolサブドメインalternative endpointとして動作させる事ができます (RFC7838 HTTP Alternative Services 参照)

SvcParamsとして、使用するポート番号、HTTP/2やHTTP/3に対応していることを示すalpnの識別子、TLS Encrypted Client Helloの情報を付加しています。

また、HTTPSレコードを使用しているだけで、このドメインに対してHTTP Strict Transport Security(HSTS)が適応されます。