セキュリティトークンを識別するための secret-token URI Scheme の提案仕様

セキュリティートークンを間違えて公開してしまうセキュリティインシデントが増えています。例えば、シークレットやトークンをソースコードに埋め込んだままコミット・公開してしまったりなどです。

機械的にセキュリティトークンを識別できるようになれば、意図せずそのようなセキュリティトークンがコミットされたり公開されるのを機械的に防げるようになります。

先日IETFに提出された「The secret-token URI Scheme」という仕様ではsecret-token URI Schemeを定義し、セキュリティトークンを識別できるようにします。

トークンにsecret-token:を付けます

 secret-token:E92FB7EB-D882-47A4-A265-A0B6135DC842%20foo

この仕様はIETFのART WGで議論されるようです。

Cookieにかわる Sec-HTTP-State ヘッダの提案

Cookieの様々な問題を解決するために、Webセキュリティー界隈で活躍されるMike West氏から「Tightening HTTP State Management」というCookieに変わるHTTPにおいてステートを扱う仕組みが提案されています。

現在はIETFのHTTPbis WGのMLに投稿されただけで仕様が正式にinternet-draftとして提出されたものではありません。まだまだどうなるかは全然わからない状態です。

この提案では、現在のCookieはセキュリティと非効率性とプライバシーの問題があると言っています。

現在のcookieは、Same-Origin-Policyとは異なりオリジンを超えて共有されたり、パスを指定して共有されたりもします。また、Secure属性やHttpOnly属性の利用率は10%以下であり、SameSite属性では0.06%以下となっています。使用されているデータ量も多く、ブラウザによる統計の中央値ではドメインあたり409バイト、99パーセンタイルでは4,601バイトにもなります。

ここまでのCookieの改善など

Cookieをどうにかしたいという要望は根強く、2010年にもAdam Barth氏より「Simple HTTP State Management Mechanism」という提案仕様でcookieならぬ"cake"ヘッダが提案されていました。その後「Origin Cookies」と改題されましたが標準化されることはありませんでした。

既存のCookieの仕様である「RFC 6265 - HTTP State Management Mechanism」に"Cookie Prefixes"や"Same-Site"を追加した改定仕様も進行中ですが、その利用率は低いままです。
asnokaze.hatenablog.com

そういった中で、Cookieに変わる新しいステート管理の新しい仕組みを定義し、Cookieから徐々に移行できるようにと出てきたのが「Tightening HTTP State Management」です。

Sec-HTTP-Stateヘッダ

Cookieの持つ様々な問題を解決するために、「Simple HTTP State Management Mechanism」の仕様では、ブラウザがセキュアなオリジン(HTTPS, WSS)にアクセスする際に256bitのトークンをSec-HTTP-Stateヘッダに付加して送信します。

Sec-HTTP-State: token=*J6BRKagRIECKdpbDLxtlNzmjKo8MXTjyMomIwMFMonM*

サーバはこのトークンを用いてステート管理を行うことになります。

このSec-HTTP-Stateヘッダは以下の特徴を持ちます。

  • Clientがトークンを発行します
  • このトークンはJavaScriptやService Workersからはアクセスできない
  • この256bitのトークンはオリジン毎に生成され、そのオリジンのみに送信されます
  • 非セキュアなオリジン(HTTP, WS)では生成されない
  • same-siteへのリクエスト時のみ送信される(Third-Partyには送信されない)
  • トークンはサーバ、ユーザ、ブラウザによってリセットされるまで保持される

もちろん、サーバ側からトークンを発行可能にするかなどの議論はされるでしょう。

Sec-HTTP-State-Optionsヘッダ

サーバ側からトークンのオプションを指定する事もできるようになっています。HTTPレスポンスでSec-HTTP-State-Optionsヘッダで指定します。すでにいくつか考えられています。

Cross-Siteアクセス

Sec-HTTP-State-Options: ..., delivery=cross-site, ...

Sec-HTTP-State-Options: ..., delivery=same-origin, ...

TTL

Sec-HTTP-State-Options: ..., ttl=3600, ...

Sec-HTTP-State-Options: ..., ttl=0, ...

NginxでTLS1.3の0-RTTハンドシェイク (early_data)を試す

昨日、NginxがTLS1.3の0-RTTハンドシェイクをサポートしたので試した。無事動作することが確認できた。

該当コミットはこの2つ

TLS1.3の0-RTTハンドシェイクは、一度ハンドシェイクをした相手とはClientHelloに続けてアプリケーションデータ(HTTPリクエスト)を送信することで、より早くデータのやりとりを開始する方法です。

f:id:ASnoKaze:20180808013052p:plain
(引用: https://blog.cloudflare.com/tls-1-3-overview-and-q-and-a/)

通常のResumptionよりも1-RTT分早くHTTPリクエストを送信されることになります。しかし、このデータは再送攻撃が可能ですので、冪等なリクエスト以外はearly_dataを拒否すべきです。詳しくは以前書いた記事を参照
asnokaze.hatenablog.com

BoringSSL

コミットログに書かれている通り、BoringSSLを使用する必要があります。
基本的には公式のビルド手順のとおりです

(ninjaの公式ページからninjaをダウンロードしておく)

git clone https://github.com/google/boringssl.git
cd ./boringssl

mkdir build
cd build
cmake -GNinja ..
ninja

nginxのビルド準備

#./boringsslのディレクトリ
mkdir -p .openssl/lib 
cd .openssl 
ln -s ../include . 
cd ../ 
cp build/crypto/libcrypto.a build/ssl/libssl.a .openssl/lib

nginxのビルド

wget http://hg.nginx.org/nginx/archive/tip.tar.gz
tar zxvf ./tip.tar.gz
cd ./nginx-ba971deb4b44 #解凍したディレクトリ

./auto/configure  --with-openssl=/PATHTO/boringssl/ --with-http_ssl_module
make

config

nginx.conf内で、ssl_early_data on と指定することで0-RTT early_dataが有効になります

    server {
        listen       443 ssl ;
        server_name  localhost;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

        ssl_early_data on;
...

アクセスしてみる

nginxを起動する

sudo ./nginx-ba971deb4b44/objs/nginx

せっかくなので boringssl のtoolを使う

cat ./boringssl/build/request.txt //early_dataをtxtに書いておく
GET / HTTP/1.1
host:localhsot


./boringssl/build/tool/bssl client -tls13-variant draft28 -connect 127.0.0.1:443  -test-resumption -early-data @./request.txt
Connecting to 127.0.0.1:443
Connected.
  Version: TLSv1.3
  Resumed session: yes
(略)
  Early data: yes #★ Early data: yesとなる 

HTTP/1.1 200 OK
Date: Tue, 07 Aug 2018 16:25:00 GMT
Content-Type: text/html
(略)

nginx ログ

nginxのログでも、$ssl_early_data でearly_dataがあったか確認できる

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '$ssl_protocol $request_time early=$ssl_early_data';

こんな感じのログが出る

127.0.0.1 - - [07/Aug/2018:16:19:15 +0000] "GET / HTTP/1.1" 200 612 "-" TLSv1.3 0.000 early=1

Fetchの仕様で application/report を送信時にCORSが必要になった

以前このブログでも書いたNetwork Error Loggingなど、Webサイトを表示する際に発生した問題のレポートを指定されたエンドポイントに送信する機能が増えてきている。
asnokaze.hatenablog.com

このレポート送信に関する仕様はReporting APIで定義されている。

一方で、Fetchの仕様としてCORSを送信する必要のないContent-Typeは下記の通りになっている 。見ての通り、レポート送信時に使用される content-type である

  • `application/csp-report` [CSP]
  • `application/report` [REPORTING]
  • `application/expect-ct-report+json` [EXPECT-CT]
  • `application/xss-auditor-report`
  • `application/ocsp-request` [OCSP]

この除外リストが出来るまでの議論はいぜん書いたとおり
asnokaze.hatenablog.com

Remove Reporting API from CORS exceptions

上記の除外リストから、application/reportを取り除くようである
github.com

そのため、Reporting API を使用している場合は、CORS対応を対応する必要が出てくる。Network Error Logging は対応必須である。一方で、report-uriディレクティブで個別にレポート先エンドポイントを指定してるCSPやExpect-CTは対応する必要はない。

実装

Reporting: Send CORS preflight before uploading reports」で、Chromeはすでに実装が入っている。

Chrome Dev(69)で実際にnelヘッダを試すとOPTIONSが飛んでくることが確認できた

2018/07/27 01:18:24 [debug] 4815#0: *86 http2 http request line: "OPTIONS /report HTTP/2.0"

Clear-Site-Dataヘッダでブラウザに記憶されているデータを消す

Webブラウザは表示したサイトに関する様々なデータを記憶しています

例えば

  • cookie
  • cache
  • HTTP認証の情報
  • localStorage
  • service worker registrations

しかしサーバ側からこれらのデータを明示的に消すのは難しい場合があります。例えば、httpOnlyのcookieは現在ブラウザにどのようなCookieがセットされているか知るのは難しいでしょう。

そこで、そのようなデータを消す Clear-Site-Data レスポンスヘッダW3Cで議論されています。実は、3年前に「Clear Site Data、ブラウザのローカルデータを削除する仕組み」で書いたときから微妙な変更が入っている。

また、ブラウザへの実装も進んでおり試せるような段階となってきている。

試す

こんな感じのヘッダを付けて、Chromecookieが消えるのを確認した

Clear-Site-Data: "cache", "cookies", "storage"

ちなみに仕様上指定できるのは

雑にCookieを設定する

f:id:ASnoKaze:20180724020335p:plain

消える

reloadしてClear-Site-Dataレスポンスヘッダを受け取ると消える。
executionContextsや、HTTP認証情報などは現状消えないが概ね動作している模様
f:id:ASnoKaze:20180724020714p:plain

ブラウザの廃止される機能を使っていることを検知する 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では何か動きがあるかもしれません。