ブラウザのネットワークエラーをレポートさせるNetwork Error Loggingが来た

20180727追記
CORS対応が必要になりました
asnokaze.hatenablog.com

20180703追記
ドキュメントはhttps://w3c.github.io/network-error-logging/ にが移されました

20180608追記
仕様上は、jsonの各値はハイフンではなく、アンダースコアを使用するようになります

  • report-to => report_to
  • max-age => max_age
  • ... etc

https://github.com/WICG/network-error-logging/commit/86c4d1c0fa4c5d5ca1d8bdcd9fa931e7e4ab65c2

こんな感じ

nel: {"report_to": "network-errors", "max_age": 2592000, "include_subdomains": true, "success_fraction": 1}
report-to: { "endpoints": [{"url" : "https://asnokaze.com/report", "priority": 1}], "group": "network-errors", "max_age": 10886400, "include-subdomains":true}


以下本編


TCPコネクションタイムアウトTLS証明書エラー・名前解決エラー・リダイレクトループなど、ブラウザでは様々なネットワークエラーが発生します。ユーザ側の環境にも依存するため、サーバ側からは検知できない場合もあります。

そういったブラウザで発生したネットワークエラーをレポートさせる「Network Error Logging」がついに、Chrome開発版(dev) で利用できるようになったので試してみる

たまにdisableになってたりするけど、再起動すると使えたりする。。。

Network Error Logging

Network Error Logging」は、W3CのWICGで議論されている仕様です。

HTTPレスポンスヘッダで、nelヘッダを指定することでネットワークエラーを指定したエンドポイントに対してレポートするようになります。レポート先エンドポイントは「Reporting API」で定義されるように、report-toヘッダで別途指定します。

指定例

nel: {"report-to": "network-errors", "max-age": 3600, "include-subdomains": true,"success-fraction": 0}
report-to: { "endpoints": [{"url" : "https://asnokaze.com/report"}], "group": "network-errors","max-age": 10886400, "include-subdomains":true}

nelヘッダでは以下のような指定ができます

  • report-to: エンドポイントのグループ識別子(別途report-toヘッダで指定する)
  • max-age: このヘッダで指定される指示の有効期限
  • error-fraction: エラー発生時にレポートを送信する割合。1.0~0.0の間で指定
  • success-fraction: エラーが発生していなくてもレポートを送信する割合。1.0~0.0の間で指定
  • include-subdomains: サブドメインのネットワークエラーもレポートするか

このように指定すると、以後そのドメインでネットワークエラーが発生した場合に以下のようにレポートがPOSTされる。
404エラーが発生した場合と、名前解決エラーが発生した場合のレポート例です(jsonは整形済み)

どのページで、どういたネットワークエラーが発生したか確認できる。

[
	{
		"age": 240003,
		"report": {
			"elapsed-time": 33,
			"protocol": "http/1.1",
			"referrer": "https://asnokaze.com/nel.html",
			"sampling-fraction": 1,
			"server-ip": "160.16.124.39",
			"status-code": 404,
			"type": "http.error",
			"uri": "https://asnokaze.com/img/b.gif"
		},
		"type": "network-error",
		"url": "https://asnokaze.com/img/b.gif"
	},
	{
		"age": 147358,
		"report": {
			"elapsed-time": 7,
			"protocol": "",
			"referrer": "https://asnokaze.com/nel.html",
			"sampling-fraction": 1,
			"server-ip": "",
			"status-code": 0,
			"type": "dns.name_not_resolved",
			"uri": "https://nothing.asnokaze.com/"
		},
		"type": "network-error",
		"url": "https://nothing.asnokaze.com/"
	}
]

動作確認

Chromeの「chrome://net-internals/#reporting」より、Network Error Loggingが有効であること、レポートとして送信されるデータが確認できる
f:id:ASnoKaze:20180528205145p:plain

一応、NEL確認用ページ
https://asnokaze.com/nel.html

エラーの種類

Network Error Loggingでは様々なエラーが定義されています。

  • ok エラーはない
  • dns.unreachable DNSサーバへ到達できない
  • dns.name_not_resolved DNSサーバは応答したが名前解決に失敗
  • dns.failedRequest 上記以外の理由で名前解決エラー
  • tcp.timed_out TCP接続タイムアウト
  • tcp.closed TCP接続がクローズされた
  • tcp.reset TCP接続がリセットされた
  • tcp.refused TCP接続が拒否された
  • tcp.aborted TCP接続が中断された
  • tcp.address_invalid TCP接続のアドレスが正しくない
  • tcp.address_unreachable TCP接続のアドレスへ到達できない
  • tcp.failed 上記以外の理由でTCP接続が失敗した
  • tls.version_or_cipher_mismatch TLSのバージョンや暗号が合わない
  • tls.bad_client_auth_cert クライアント認証が正しくない
  • tls.cert.name_invalid 証明書の名前が正しくない
  • tls.cert.date_invalid 証明書の有効期限が正しくない
  • tls.cert.authority_invalid 証明書のauthorityが正しくない
  • tls.cert.invalid それ以外の理由で証明書が正しくない
  • tls.cert.revoked 証明書が執行している
  • tls.cert.pinned_key_not_in_cert_chain key pinningのエラー
  • tls.protocol.error TLSプロトコルエラー
  • tls.failed それ以外の理由でTLS接続が失敗した
  • http.protocol.error HTTPプロトコルのエラー
  • http.response.invalid レスポンスが空やcontent-lengthが不一致、そのたユーザエージェントがレスポンスの処理を中断
  • http.response.redirect_loop リダイレクトループ
  • http.failed 上記の理由以外でHTTPエラー
  • abandoned ユーザによる中断
  • unknown 不明

今後

Blinkの開発者MLでChromeへの導入について議論している
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/nNji_u7BRxo

このまま行けば、Chrome 68の安定版にも入ってくるだろう

GREASE for HTTP/2 の提案仕様

AkamaiのMike Bishop氏から、「GREASE for HTTP/2」という提案仕様が出ています。

HTTP/2では、未知のフレームタイプとSETTINGSパラメータは無視するようになっています。これは、将来HTTP/2を拡張できるようにするためで、実際に「RFC 8336 The ORIGIN HTTP/2 Frame」では新しくORIGINフレームを定義しています。新しい機能をつかっても、未対応な実装にはただ無視されるだけですので、利用しやすいです。

本来は未知のフレームやSETTINGSは無視すべきですが、未知のSETTINGSパラメータによって通信を終了する実装があるようです(URL)。このような実装は、将来の拡張を妨げる原因になります。

そこで、HTTP/2にもGREASEを導入するのが今回の提案です。また、HTTP over QUICにおいても同様の仕組みが盛り込まれるかもしれません。

GREASE for HTTP/2

GREASEとは

TLSにおけるGREASE、「Applying GREASE to TLS Extensibility」についての解説が詳しいです
jovi0608.hatenablog.com

ちゃんと、未知のパラメータが無視されるように、GREASE用の意味を持たないパラメータを送信します。これによって、日頃から未知のパラメータを受け取っても不具合を起こさず無視する実装であることを確認します。

こうすることで、実際にプロトコルを拡張する前、実装者は未知のパラメータを受け取ったときに不具合があれば気づけるようになります。

GREASE for Frame Types

0xb + (0x1f * N) のフレームタイプをGREASE用に予約します。このフレームはまったく意味を持っておらず、PADDINGの代わりに使用できます。

具体的には、0x2A (42), 0x49(73), 0x68(104).... などのフレームタイプ番号です。

GREASE for SETTINGS

"0x?a?a" のSETTINGSパラメータをGREASE用に予約します。このSETTINGSはまったく意味を持っていません。

具体的には、0x0a0a (2570), 0x1a1a(6682), 0x2a2a(10793).... などのSETTINGSパラメータです。

Sec-Metadataヘッダについて

20190215追記
Sec-MetadataはFetch Metadataになりました
asnokaze.hatenablog.com


CSRF攻撃やクロスドメインリクエストに対してサイドチャネル攻撃をすることで、情報がリークすることがあります。

それを防ぐために、どのようにHTTPリクエストが行われたかサーバサイドでより詳しく判断できるように、Sec-Metadataヘッダという仕様がW3Cの WebAppSec WGで議論されています。仕様については提案者のMike West氏のリポジトリに説明があります「Sec-Metadata (TODO: Bikeshed the name)

すでに、Chromeへの導入も検討されています。
Intent to Implement: The `Sec-Metadata` HTTP request header.

例を見るとより分かりやすいと思います

Sec-Metadataヘッダ

たとえば、銀行のWebサイトで講座を操作するエンドポイント(リクエストをうけるURL)が、タグでクロスドメインでアクセスされることはないはずです。

Sec-Metadataヘッダは、そのHTTPリクエストがどのようなリクエストなのか情報を付加します。

以下は例です。

// <picture>
Sec-Metadata: initiator=imageset, destination=image, site=cross-site, target=subresource

// Top-level navigation
Sec-Metadata: initiator="", destination=document, site=cross-site, target=top-level, cause=user-activation

// <iframe> navigation
Sec-Metadata: initiator="", destination=document, site=same-site, target=nested, cause=forced
  • initiator及び、destininationは どのようにしてリクエストがトリガーされたかわかります。
  • targetは、browsing contextを示すtop-level, nested, subresourceのどれかになります
  • siteは、same-origin, same-site, cross-siteのどれかです
  • causeは、user-activation、forcedです。URLバーへの入力などユーザのアクションによってリクエストが行われたのか、window.locationなどユーザの意志とは別にリクエストが行われたのか識別できます

これらの情報を元に、サーバでは想定していないかどうか識別できるようになります。

Web5Gとはなんなのか

W3Cでは、「Web5G」を掲げ5G及び関連するネットワークの進化に向けて、それにあわせたWeb標準技術・APIを模索しているようである。

個人的な印象としては、ネットワークレイヤとWebアプリケーションレイヤが連携するようなイメージでいる。ネットワークを性能ごとに切り出して提供するネットワークスライスや、ネットワークエッジで処理を行うモバイルエッジコンピューティング(MEC)を具体的に想定しているものもあれば、そうでないものもある。

すでに幾つかの資料がネット上に上がっており、僕は5Gは全然詳しくないが、今回は「Web5G Roadmap」と「Web5G Workshop」を眺めつつ、どのような事が思い描かれているかみていく。

5Gとどのように関わるかわからないが、BBCのネットワークエッジまで HTTP over QUICマルチキャストで配信する例は非常に興味深い

Web5G Roadmap

W3Cのロードマップの中に「Web5G Roadmap」というページがある。既に標準化が進められている仕様の他に、「Features not covered by ongoing work」として将来思い描いている機能の一部が紹介されている。

特に「Network Control」に書かれている部分は興味深い

Real-time adaptative to live network conditions

エッジに設置され使用されるマルチアクセスエッジコンピューティング(MEC)によって、現在のネットワーク環境をリアルタイムにサーバ(クライアントへも?)に通知されるようなネットワークの登場が考えられている。そのときにブラウザはアプリケーションにどのような情報を提供すれば良いのか考えているようだ

セルラネットワークから、サーバへの情報提供可能にするメカニズムとプロトコルIETFで議論されているようだ。
Mobile Throughput Guidance Inband Signaling Protocol

Adaptation to cost of network operations

以前書いた、Mobile Data Plan Sharing APIのように、ユーザでデータPlanと連携する仕組み。ユーザが使っていない時にあわせてバックグラウンドで同期する仕組みなどを一般化できるか考えているようだ
asnokaze.hatenablog.com

Network-provided optimizations

WebRTCでは、アプリケーションプロパイダがNATやファイアウォールを超えるためのリレーサーバ(TURNサーバ)を提供しています。

ネットワーク事業者がこれらをサービスとして提供できるようなる仕組みが、「Operator-Assisted Relay Service Architecture (OARS)」で考えられている

Prioritization in enterprise networks

AppleCiscoは、ビジネスアプリケーションに最適化されたエンタープライズネットワークを提供するために協力してきました(URL)。これをWebアプリケーションへも拡張できるか?

Web5G Workshop

5/10 ~ 5/11にかけてイギリスで「W3C Web5G Workshop」が行われました。その資料が上がっているので幾つか絵を紹介する

Enabling the thrilling applications that will drive usage of 5G networks

Web技術やプロトコルの進化や利用の広がりがまとめられている(ppt URL)。その中で「Integration of the Network Protocol Layer」というスライド、Webとネットワーク制御レイヤが連携する図が出ている。

以下の図では2つの例が出ており、ブラウザからネットワークの情報を取得したりパラメータをセットする。

  • ブラウザから、Network Controle Endpointに対し現在のネットワーク状況を問い合わせ取得する。取得した情報をJavaScript APIでアプリケーションに提供する
  • ブラウザからNetwork Controle Endpointに対してnetwork adaptationを要求し、ネットワークに対してQoSが設定される

f:id:ASnoKaze:20180517012822p:plain

Network advances for Media: Server Push

BBCの発表(スライドURL)。動画は、MPEG-DASHでユニキャスト配信されており、その量が増えているという話のようだ。

そのなかで、ネットワークエッジにデバイスを設置し、そこまでマルチキャストで配信して、そこからユニキャストで配信などやっているようである。

BBCではQUICの利用を考えているようで、IETFでもQUICを用いたマルチキャストやサーバプッシュに関する拡張を提案している。

workshopでのこの一枚が象徴的で、ネットワークエッジまで HTTP over QUICマルチキャストで配信し、そこから先をユニキャストで配信することを考えているようである
f:id:ASnoKaze:20180517013810p:plain

Immersive Web & 5G

サムスンのWeb, XR, 5Gに関する発表(スライドURL)。

おそらく、低レイテンシで帯域が増えるとゲームやXRにとって良いという話

The evolution of the Web to enable greater network collaboration

IETFでのworkの話。レイヤが違くてあまり良くわからない...

Web5Gとはなんなのか

よく分からない

プロトコルにおける「堅牢性原則」は害悪か

Internet Architecture Board (IAB)でもあるMartin Thomson氏から「The Harmful Consequences of the Robustness Principle」という文書が提出されている。

これは、堅牢性原則(Robustness Principle)について言及している文書である

Robustness Principle

プロトコルの設計と実装に関する原則として、「送信するものに関しては厳密に、受信するものに関しては寛容に」と掲げる堅牢性原則(Robustness Principle)というものがある。

TCP/IP, SMTP, DNS, FTPなどの開発に関わった故ジョン・ポステル氏によって提唱され、ポステルの法則とも呼ばれている。

Wikipedia(ジョン・ポステル)によると

元々はポステルがTCPを規定した RFC793 において
相互運用性を確保するためにTCPの実装が持つべき性質として要約した節が
より一般化されて知られるようになったものである。

と書かれている。

当時の仕様の曖昧性や解釈の違い、実装のバグなどがあったとしても、極力通信が続けられるようにという原則である。プロトコルがデプロイされ使われるようにするため、このような原則となっている。

1996年に発行された RFC1958 Architectural Principles of the Internetでも「Be strict when sending and tolerant when receiving」と書かれている。

The Harmful Consequences of the Robustness Principle

提出された「The Harmful Consequences of the Robustness Principle」では、堅牢性原則(Robustness Principle)では、バグのある実装との通信を可能とするために受信側が寛容性を持つと、バグを定着させることになり、長期的なプロトコルのメンテナンス(拡張)を難しくすると述べています。

JSONの例があげられており、元の仕様であるRFC4627「The application/json Media Type for JSON」ではUnicodeの処理、オブジェクトメンバーの順序付け、数値のエンコーディングなど、詳細に書かれておらず、実装によってさまざまな解釈がされた。更新された RFC7159でも問題は解決されておらず、サブセットを定義し問題ある部分の仕様を禁止したRFC7493 I-JSON とも相互運用できていない。そのため、広くは使用されておらずJSONパーサは、[ECMA262]で指定されたより正確なアルゴリズムを実装している。

その他にもTLSのバグのある実装と通信を可能にするためのワークアラウンドが行われていることや、HTTP/1.1の仕様の曖昧性を無くすために数年の労力を要したことなどがあげられている。

そのためこの文書では、堅牢性原則(Robustness Principle)よりも、初期設計やデプロイを超えて長期的なプロトコルのメンテナンスの継続を推奨しています。

エラーハンドフィングとフィードバック

プロトコルのメンテナンスするうえで、実装しデプロイしている人からのフィードバックが重要です。

エラーハンドリングについては、仕様に不正状態の取扱について記述されていることが理想的です。そして実装は、エラー状態からの回復を試みるのではなく、致命的なエラーとすることでそれを改善する動機を与えます。

また、自動化されたエラーレポートの仕組みは、デプロイされたプロトコルのより良いフィードバックを得ることが出来ます。実装者に不具合をレポートする仕組みは優れていますが、ユーザのプライバシに留意する必要があります。

所感

ここ数年だけを外から見ても、ossification(硬直化)と言われているように、プロトコルのメンテナンスに対するコストは上がっているように見える。エラーハンドリングやレポーティングの仕組みが充実していくのは非常に喜ばしい一方で、やはり実際に通信するためバグ実装に対するワークアラウンドが出てくるのはどうしても不可避に感じる。

HTTPの仕様改定がまた始まっているように、プロトコルのメンテナンスは継続して進めていかれるのは明らかであるし、続けていかなければならない。そのために、より良い仕組みや考え方が広まっていけばいいなあと思いました。

TLSにおけるTicketRequest拡張の提案仕様 (RFC 9149)

(追記) 2022年、RFC 9149として標準化されました

==
Appleの人らによって「TLS Ticket Requests」という、TLSでのセッション再開に利用するチケットに関する拡張仕様が提案されています。

TLSはあまり詳しくないのですが簡単に読む

TLS session ticket

まず、TLS session ticketとセッション再開について確認する


TLSでは一度ハンドシェイクを行った相手と、セッションを再開するための手順が用意されています。これにより処理量を少なくできます。

セッション情報を暗号化しTicketとしてクライアントに渡すことで、サーバ側はセッション再開のために情報を保持しておく必要がなくなります。

Ticketに関する拡張仕様は、RFC5077「TLS Session Resumption without Server-Side State」で標準化されていますし、TLS1.3の仕様でもTicketに関する定義がされています。

  • TLS1.3の仕様では、最初のハンドシェイクの際にクライアントがFinishedを送った後に、サーバからNewSessionTicketメッセージでticketをクライアントに発行します。

  • 以降セッションを再開する場合は、pre_shared_key拡張を付与してセッションの再開を行います。セッションの再開ですので、サーバから「Certificate」「CertificateVerify」は送信されません。


TicketRequest概要

現在の仕様でも複数のticketを発行できますが、その発行する数はサーバが決めています。


Appleの人らが提案している「TLS Ticket Requests」では、クライアント側からticketを要求できるようになっています。これによって、クライアント側から必要なだけticketをサーバに要求できます。


例えばHTTPSなどの通信では、同じサーバに対して複数のコネクションをはる場合もあります。それはクライアントが並列数を選ぶので、欲しいticketの数をクライアントが決めるのは合理的です。


同じticketは1回のみ使用されるべきですので、クライアント側から要求すればticketが少なすぎることもなくなりますし、逆にサーバ側から過剰にticketを発行することも防げます。

TicketRequest拡張

ハンドシェイク時にticket_request(TBD)拡張を送ることで、TicketRequestに対応しているかネゴシエーションを行います。

お互いに対応していれば、ハンドシェイク後にTicketRequestメッセージを送ることでticketを要求できます。

   struct {
       opaque identifier<0..255>;
       opaque context<0..2^16-1>;
   } TicketRequest;

Cross-Origin Read Blocking (CORB) とは

追記20180606
Chrome独自と書いていましたが、「Fetch Standard」に取り込まれていることを確認しました


すでに、Chromeで「Cross-Origin Read Blocking (CORB) blocked cross-origin response」というエラーが出るようになっております。imgタグからクロスオリジンでhtmlファイルを取得したり、タグとレスポンスのcontent-typeが一致してない場合に出ます。


もともと、このChromeにCross-Origin Read Blocking (CORB)という機能を実装するという議論が、blink-devのメーリングリストに投稿されています。

Cross-Origin Read Blocking (CORB)」 に詳しい説明があるので、CORB とはなんぞやと簡単に説明を読んで見る。

CORBはまだChromeで議論されている仕組みであり、他のブラウザやクライアントでそのまま適応されるものではない点注意

Cross-Origin Read Blocking (CORB)

CORBとは、一言でいうと、ある種の攻撃を防ぐために、画像デコーダJavaScriptエンジンがクロスオリジンのリソースを読み込む前にブロックする仕組みです。


imgタグやscriptタグは他のドメインのリソースを読み込むことが出来ます。これは、Cookieが付くのでそのユーザのみがアクセス出来るリソースだったり、そのユーザが属しているプライベートネットワークのみからアクセスできるリソースだったりします。

例えば、下記のように他ドメインjsonファイルを読み込むような下記要素を用意します

<script src = "https://example.com/secret.json">

XSSI攻撃といった、JavaScript Arrayコンストラクタを上書きすることで内容を読みとることができたり。その他にも多くの攻撃手法が見つかっています。(参考PDF)

また、img要素でも、ロードしメモリ上に配置された後にサイドチャネル攻撃でその中身を読み取る方法も可能性としてあります。

<img src="https://example.com/secret.json">

CORBはクロスドメインのリソースにおいて、JavaScriptエンジンや画像デコーダが受取る前に読み込みをブロックする仕組みのようです。

CORBにおけるブロック

CORBによって保護される必要があると判定された時、レスポンスは以下のように変更されます

対象となる読み込み方法

下記の手段で取得されるリソースが、CORB保護対象となり得る

  • XHR and fetch()
  • ping, navigator.sendBeacon()
  • <link rel="prefetch" ...>
  • “image” requests like <img> tag, /favicon.ico, SVG‘s <image>, CSS’ background-image, etc. script-like destinations like <script>, importScripts(), navigator.serviceWorker.register(), audioWorklet.addModule(), etc.
  • “audio”, “video” or “track”
  • “font”
  • “style”
  • “report” requests like CSP reports, NEL reports, etc.

<iframe>, <object>, <embed>は別のセキュリティで保護されており、別のプロセスで実行されるため推測は困難(らしい

レスポンスがCORBで保護されるかの条件

レスポンスがJSON、HTML、XMLの場合に保護対象になります。

  • X-Content-Type-Options: nosniffの場合、Content-TypeがHTML MIME type・JSON MIME type ・XML MIME type・text/plainの場合 (image/svg+xmlを除く)
  • レスポンスが206の場合、Content-TypeがHTML MIME type・JSON MIME type ・XML MIME typeの場合 (image/svg+xmlを除く)
  • それ以外の場合はレスポンスボディを確認します
    • HTML MIME type のうちHTMLとだと思われるもの
    • XML MIME typeのうちXMLだと思われるもの
    • JSON MIME typeのうちJSONだと思われるもの
    • text/plainのうちJSON, HTML, だと思われるもの

上記MIME typeの定義はこちら

demo

オプションを付けて起動すると動作するらしい
https://anforowicz.github.io/xsdb-demo/index.html

consoleに下記のように表示される

Blocked current origin from receiving cross-site document at https://www.chromium.org/ with MIME type text/html.
その他

ドキュメントには、現在のWebへの影響・互換性や、さらに詳しいアルゴリズムなどの解説などもある