Network Error Loggingを用いたポートスキャン手法について

20180711追記 この問題は解決されました
Handle errors in different phases differently #83

  • include_subdomains はDNSの名前解決エラーのみをレポート出来、TCP関連のエラーは通知できません。
  • ReportingObserver で、Network Error Loggingは監視できません
  • DNS Rebinding を防ぐため、ポリシーを適応したIPアドレスを覚えておきます。IPアドレスが変更した場合レポートは送信されません

先日、紹介した「Network Error Logging」を使用することでユーザのプライベートネットワークをポートスキャン可能であることを開発者様に報告した。

その手法と、仕様上の問題点について説明する。

仕組みは単純なので、もっと早く気づけても良かったかもしれない...orz

Network Error Logging

前回紹介したとおり、ブラウザで発生するネットワークエラーをレポートとして受け取れるようになる仕様である。
asnokaze.hatenablog.com

レスポンスを返す際に、nelヘッダを指定すると、そのページを閲覧している際に発生する、TCPコネクションタイムアウトTLS証明書エラー・名前解決エラー・リダイレクトループなどが、レポートとして指定したエンドポイントに提出される。

nel: {"report-to": "network-errors", "max-age": 360, "include-subdomains": true,}

例えば、画像が404で読み込めなかったりすると、こんな感じのJSONが指定したエンドポイントにPOSTされる

	{
		"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"
	},

ポートスキャン手法

Network Error Loggingでは、include-subdomainsを指定することでサブドメインのリソースに対するネットワークエラーもレポート対象に含めることができる。

例えば、example.comサブドメインとしてプライベートIPのサブドメインを用意する。具体的には127.0.0.1と名前解決されるような127-0-0-1.example.comという感じである。

example.comへのアクセスで、include-subdomainsを指定してnelヘッダを返してやる

NEL: {"report-to": "nel", "include-subdomains": true,
      "success-fraction": 1.0, "failure-fraction": 1.0}

あとは、HTML内に、こんな感じで用意したサブドメインへリクエストが飛ぶようにしてやる。

<img src="https://127-0-0-1.example.com:2000" />
<img src="https://127-0-0-1.example.com:2001" />
<img src="https://127-0-0-1.example.com:2002" />
<img src="https://127-0-0-1.example.com:2003" />

Network Error Loggingでは、以下のようなTCPエラーが定義されているため、既存の手法(onerrorイベント)よりも多くの情報を得ることが可能である

  • tcp.timed_out TCP接続タイムアウト
  • tcp.closed TCP接続がクローズされた
  • tcp.reset TCP接続がリセットされた
  • tcp.refused TCP接続が拒否された
  • tcp.aborted TCP接続が中断された
  • tcp.address_invalid TCP接続のアドレスが正しくない
  • tcp.address_unreachable TCP接続のアドレスへ到達できない

直接的になにかの脅威があるわけではないが、何かしらの攻撃の足がかりになる可能性も考えられる

仕様上の問題点

すでに上記問題は、仕様の問題として議論がされている
https://github.com/WICG/network-error-logging/issues/74

主には2点

  • サブドメインのリソースをレポート対象に含めるべきか。CORSのようなそのサブドメインで動作するサーバの許可を得るか、サブドメインの指定をそもそもできなくする
  • TCPのエラー情報などを実際に取得可能にしてよいのか。例えば、Fetch APIでは詳細エラーを取れるようにしてほしいという意見が出るが、今の所そのようにはなっていない。

Same-Origin Policyを超えて設定が指定されること、サブドメインにプライベートIPが指定されうることは、結構良くないパターンがありそうですね。パットは思いつかなかったが、他の仕様でもなんかあるかもしれない。(cookieとか)

あらためて、新しい機能を作るって難しいなと実感しました。

Cross-Origin-Resource-Policyヘッダとは

Cross-Origin-Resource-PolicyヘッダというのがSafari 12でサポートされるらしい

もともとは、W3C側でFrom-Originと呼ばれていた仕組みらしいが、Fetch Starndardに入れる議論がされているようだ。

github.com

このCross-Origin-Resource-Policyヘッダを用いることで、自分サイトでホストしている画像やJavaScriptなどのリソースをクロスオリジンで他所のサイトで表示・利用されることを防ぐことができる。

https://example.com/img.jpg を<img>タグで呼び出せるのはexample.comのサイトだけで、https://asnokaze.comから<img>タグで画像を埋め込んでも表示することができなくなる。

Cross-Origin Read Blocking (CORB) とは」でも書いたように、昨今サイドチャネルなどの攻撃によってリソースなどのデータが第三者に読み取られる可能性があるため、それらの攻撃を防ぐのを目的にしている。( Issue参照 )

サイドチャネルを行う目的のサイトで、本人しか見えない画像や、http://localhost/img.pngを読み込まれて、中身を見られたりしたら困るわけだ。

Cross-Origin-Resource-Policyヘッダ

画像やJavaScriptなどのリソースを返すときに、レスポンスヘッダにつける。

Cross-Origin-Resource-Policy: same-origin

(WWDCではヘッダ値はsameと書かれていたが、Fetchの仕様ではsame-origin/same-site)

  • same-originは同一オリジンの場合のみ許可される
  • same-siteはhttpsかつ同じホスト名の場合のみ許可される

まだ議論中なので、実際どうなるかはわからない

QUICの現状確認をしたい 2018/5 (Stream 0の再設計案などなど)

IETFでは引き続き、QUICの標準化が進められています。


次回
asnokaze.hatenablog.com

前回分
asnokaze.hatenablog.com


現状確認したい

ちょうど先週に、コアドキュメントのdraft-12も出ています

例えば大きなところで、draft-11で「Coalescing Packets」が入り複数のQUICパケットを一つのUDPデータグラムに格納できるようになった。draft-12ではパケット番号の暗号化などの更新が含まれています。これによって、通信経路上ではパケットを観察してもほとんどの情報が見えなくなりました。

また、HTTPヘッダの圧縮の仕様であるQPACKもwg draft-00が出し直されており、大きな差分があります。

ホットトピックとして、後述するStream 0の再設計や、ECNサポートがあります。
6月4~5日に行われる、QUIC WGの中間会合で議論されることでしょう。
wg-materials/agenda.md at master · quicwg/wg-materials · GitHub

相互接続テスト状況

QUICでは、draftバージョンの実装を持ち寄って相互接続テストを定期的に行っています。
現在は、「5th Implementation Draft」としてテストしています。

f:id:ASnoKaze:20180530013031p:plain

Stream 0 Design Team

draft-12のQUICでは、Stream 0上でTLS1.3のメッセージをやり取りして、そこから通信を暗号化するための鍵を共有します。

このStream 0上でのTLS1.3のやりとりする設計は、IETF101で問題が提起されました。その時の発表資料は、「wg-materials/Stream0-EKR.pdf at master · quicwg/wg-materials · GitHub」で公開されています。

以前以下の記事でも書いたとおり、Stream 0上でCrypto handshakeを行うため、Stream 0の再送や信頼性について特殊扱いすることになっています。ストリームは転送順番やロスが回復されますが、そのためのメッセージもQUICでは暗号化されますが、Stream 0では鍵の共有を行っている途中というわけです。(僕の認識が違ったらすみません)

QUIC over DTLSの議論も行われましたが、変更が大きすぎる点やDTLS自体への変更も考える必要があるため、QUIC over DTLSの方向ではなく、Stream 0を再設計する方針となりました。
asnokaze.hatenablog.com

Stream 0 の再設計には、デザインチームが結成されました。
この「Stream 0 Design Team」は、MLにかかれている通り、ガチ勢ばかりです。

Stream0 Design Team Proposal

そのStream 0 Design Teamによる、提案が出てきました。

Documentの方の図を見ると、どのような変更がされたのかがよくわかります。

draft-12では以下のような感じです
f:id:ASnoKaze:20180530011328p:plain
stream 0でTLSレコードをそのまま送信します。TLSレコードには通常通り、ServerHello, EncryptedExtensions, Fin, NewSessionTicketsなどのTLSメッセージが含まれています。


提案方式では
f:id:ASnoKaze:20180530012004p:plain
Stream 0を撤廃し、新しく定義されたCRYPTO_HSフレーム上にTLSレコードではなく、TLSメッセージを直に設置しています。Stream 0を撤廃することで、Stream 0の特殊扱いはなくなります。
(CRYPTO_HSフレームは、CRYPTOフレームに改名されるかも)


おわり

この変更により、パケット番号空間や再送らへんもいろいろ変更が入っています。ちょっと細かいところまで理解が進んでいないので、時間をかけて差分を読んでいきたいです

ブラウザのネットワークエラーをレポートさせる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とはなんなのか

よく分からない