ブラウザの廃止される機能を使っていることを検知する Deprecation Reports (+ Intervention reports )

20180713追記 Intervention reports について追記しました


ブラウザのバージョンアップは定期的に行われており、その度に廃止される機能もあります。

廃止されることは公式にアナウンスされますが、そもそも自分が使っているかどうかすべてを把握することは難しいでしょう。JavaScriptAPIであったり、HTTPヘッダだったりとその範囲は非常に広く、ライブラリの特定のバージョン以下だと問題になるといったケースも有るかと思います。

このような場合に役に立つ、廃止される機能が使用されていることをWebデベロッパー側で検知する仕組みが「Deprecation Reports」です。

Blink開発者メーリングリストでも議論されていますが、すでにChrome Canaryで動作するので、簡単に動作確認してみます。

Reporting API

表示してるページのエラーなどを指定したエンドポイントにレポートを送信させる、「Reporting API」という仕様があります。

以前このブログでも、以下の木の様を紹介します。

この仕様に新しく、Deprecation Reportsという機能が追加されました。これによって、廃止される機能を使っている場合に検知できるようになります。

ReportingObserver

その Deprecation Reports を、これまた新しく追加された ReportingObserver を使って検知してみようと思います。
ReportingObserver はReporting APIで定義されており、何かしらのレポートを送るような時にcallbackで任意の処理を実行できます(すべてのレポートタイプがObservableではない)。

こんな感じで、デベロッパーツールから実行する

function onReport(reports, observer) {
  for(let report of reports) {
    if (report.type == "deprecation") {
      console.log("message: " + report.body.message);
      console.log("url: " + report.url);
    }
  }
}

let observer = new ReportingObserver(onReport);
observer.observe();

上記に続けて、廃止される「webkitURL」変数を参照してみると、下記のようなデータが取得できる事がわかる

  • report.body.message として 'webkitURL' is deprecated. Please use 'URL' instead.
  • report.url として https://asnokaze.com/

(その他にも、reportのbodyから id, anticipatedRemoval, sourceFile, columnNumberなどが取れる)

あとはこの情報をどこかしらに送信するなりして集計すれば良い。このようにしてブラウザが将来廃止する機能を使っていることが事前に検知することが出来るようになる。

すでにChrome Canaryでは動作する。
f:id:ASnoKaze:20180706230905p:plain

Intervention reports

同じように、ChromeはIntervention reports にも対応しています。

下記のように、JavaScriptの書いたコードで仕様変更やセキュリティ/パフォーマンス上の理由により動作が変更された場合には、Reportタイプ Intervention がレポートされます。Deprecation Reports同様 ReportingObserverで検知できます。
qiita.com

「Intervention」についての詳細は、WICGのこちらから
github.com

TLS1.0, TLS1.1 の廃止する提案仕様

TLS1.3にRFC8446が採番されRFCとして出るのを待つばかりになっている。

一方で、「Deprecating TLSv1.0 and TLSv1.1」というTLS1.0とTLS1.1の廃止についての提案仕様がIETFで出ている。

TLS1.0, TLS1.1 廃止事情

カード情報セキュリティの国際統一基準 PCI DSS では2018年6月30日以降はTLS1.1を禁止している他、アメリカ国立標準技術研究所(NIST)もTLS1.2の移行を以前から推奨している。

実サービスにおいては、GithubAmazon ELBCloudFlareなどTLS1.0, TLS1.2の廃止を進めているサービスも多い。

また、IPAの出している「SSL/TLS暗号設定ガイドライン」でも、高セキュリティ型要件ではTLS1.2だけのサポートと書かれている。また「「SSL/TLS暗号設定ガイドライン改訂及び鍵管理ガイドライン作成のための調査・検討」報告書」でも各国・各標準化組織・各ベンダーの推奨事項への調査が報告されており、興味深い。

Deprecating TLSv1.0 and TLSv1.1

セキュリティ上の問題や、上記のような情勢を考慮してIETFでもTLS1.0とTLS1.1を廃止(historic)にしようというのが、「Deprecating TLSv1.0 and TLSv1.1」での提案です。

この提案では、古いバージョンのRFCをhistoricするとともに、TLSの利用に関する推奨事項を書いたRFC7525「Recommendations for Secure Use of TLS」でも、TLS1.0, TLS1.1の利用を禁止するように更新するものです。(現状では禁止はされていない)

ML上では活発に議論はされていないようですが、来月開催されるIETF102では何か動きがあるかもしれません。

Forwarding-Loop Attacks攻撃を防ぐCDN-Loopヘッダの提案仕様

Forwarding-Loop Attacks攻撃を防ぐ「CDN Loop Prevention」 という仕様が提案されています。

背景

CDNへのDoS攻撃として、リクエストをCDN内でループさせる「Forwarding-Loop Attacks」という攻撃手法が知られています。

CDNユーザの設定ミスや、攻撃者がユーザとしてそのような設定をすることでHTTPリクエストをCDN内でループさせる攻撃です。詳しくは「Forwarding-Loop Attacks in Content Delivery Networks」(PDF) にかかれています。

単一のCDNや、もしくは複数のCDNをループさせる方式があります。

このForwarding-Loop Attacksを防ぐために、ループを検知するための「CDN-Loopヘッダ」を定義する提案仕様がAkamai TechnologiesとFastlyとCloudflareの方の共著で出されています。

CDN-Loopヘッダ

CDN Loop Prevention」では、ループ検知のためにCDN-Loopヘッダを新しく定義します。このCDN-Loopヘッダに経由したCDNを記録することで、CDNのループを防ぎます。

本来であれば、ループ検知はRFC7230で定義される「via」ヘッダを使用すべきですが、viaヘッダをその他の目的のために使用するサーバもいるため実際にはviaヘッダ使用できません。

CDN-Loopは下記のとおりである。コンマ区切りでCDNの識別子が中継されるたびに追記されていきます。もしくは、新しくCDN-Loopを増やしても構いません。また、セミコロンの後ろに任意のkey/value値を付けることも出来ます。(これは、Structured Headers for HTTPのParameterised Listsに順している模様)

CDN-Loop: FooCDN, barcdn; host="foo123.bar.cdn"
CDN-Loop: baz-cdn; abc="123"; def="456", anotherCDN

CDN及びその他の中間装置は、このCDN-Loopを削除してはいけません(MUST NOT)。そのため、オリジンサーバにもこのCDN-Loopが届くことになります。

多くのCDNでは設定でヘッダを改変することも出来ます。そのことに言及はあるものの、いまのところ具体的な署名方法などについては述べられていません。今後議論されることになると思います。

Chromeが6週間毎にTLSバージョン番号を変更していくかもしれない

[修正] ossificationを骨化と訳してましたが、硬直化に変更しました


TLS1.3の標準化が終わり、もうRFCとして出されるのを待つばかりになっている。

そんなTLSワーキンググループのメーリングリストに、ChromiumやBoringSSLの開発に携わるDavid Benjamin氏より「Enforcing Protocol Invariants」というメールが投稿されています。

これは、今後もTLSの改善可能とするために、Chromeで新しいTLSバージョンコードポイントを試していくことに対する意見を募集しているものです。

実装としてはTLS1.3と同じですが、使用するバージョン コードポイントが異なるものを使用していくことになります。

背景、ossification(硬直化)問題

この議論の背景にはTLS1.3の標準化に関する、ossification(骨化)と呼ばれる問題に対する非常につらい道のりがあります。

TLS1.3の標準化作業を進めてるとき、ChromeFacebookが実験的にTLS1.3を試していくと、世の中のファイアウォールやネットワーク上の中間機器がTLS1.3を正しく解釈できず不具合を起こすことがわかりました。

そのため、TLS1.3のバージョンネゴシエーションはそれ専用のsupported_versions拡張を定義して、そこでバージョンネゴシエーションを行います。しかし、そのsupported_versions拡張の拡張番号を勝手に使用している実装が存在したり、TLS1.2のメッセージ順序を想定した実装などにより通信がブロックされたり、フィールドテストを繰り返し問題が見つかるたびTLS1.3の仕様を修正してきました。

そのような変更の道のりは下記資料が詳しいです

このようなインターネット上に存在する正しくない実装によって、新しいプロトコルのデプロイが阻害される状態の事をIETFではossification(硬直化)と呼んでいます。

6週間ごとのTLSバージョンコードポイント試していく

将来もTLSの改善を進めていけるように、上記のような正しくない実装の存在を明らかにしossification(硬直化)を防ぐために、新しいTLSバージョンコードポイント(拡張やcipher suites)を試していくというのが、今回の議論です。

錆びついたTLSを滑らかに、GoogleによるGREASE試験 - ぼちぼち日記 のような議論もありますが、さらにアグレッシブにバージョン番号さえもGREASEを進めていく形です。

この取組では、Chrome及びGoogleのサーバで2つのTLS1.3バージョンをサポートしていくといってます。

  • TLS1.3標準のバージョン番号 (0x0304)
  • rolling alternate version

rolling alternate versionが6週間ごとに変更されるバージョンということで、TLSの正式バージョンである0x03... をさけて採番していく考えがあると言ってます。

まだまだ、案だしの段階であり具体的にどうこうという状況ではなさそうです。

コメント

すでにコメントが付いていて、反対意見は今の所ないようです。Appleの人も興味深いと好意的な意見を述べています。

googleだけでなく他の実装者もこのバージョンローリングに対応していくかもしれません。

6週間ごとにローリングしていく番号をドキュメント化するのは大変だが、wikiなどで記述できると良いよねというコメントもついている。

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

現状確認したい

ちょうど先週に、コアドキュメントの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フレームに改名されるかも)


おわり

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