HTML要素からHTTP/2優先度を指定する Priority Hints が動いた

HTTP/2にはクライアントからHTTPリクエストの優先度を指定することができる。サーバはその優先度に基づいてHTTPレスポンスを返す(無視しても良い)。
一般的にはブラウザ自身が判断し、ページのレンダリングを早くするためにCSSなどは優先度を高く、画像は優先度を低く設定している。

一方で、Webサイトを作る側としては、最初に表示される領域(Above the fold)の画像を優先度高くしてほしいと行ったこともあるだろう。

そこで、HTMLからリクエストの優先度を指示できる「Priority Hints」という仕様の標準化が進められている。

すでに、Chrome Canary (71)で動作するようなので試す。

importanceに"high"や"low"を指定する

     <img src="img/1.png" importance="high">
     <img src="img/2.png" importance="low">
     <img src="img/3.png" importance="low">
     <img src="img/4.png" importance="high">

デベロッパーツールで確認すると
f:id:ASnoKaze:20180912010303p:plain

Priorityの欄が指定したとおりになってる事が確認できる。

仕様

importanceには以下が指定できる

  • high
  • low
  • auto

その他

動作確認はしていないが、その他にもいくつかの使用例が書かれている

preloadでも

HTMLから

<link rel="preload" as="script" href="critical-script.js">
<link rel="preload" as="style" href="theme.css" importance="low" onload="this.rel=stylesheet">

レスポンスヘッダから

Link: </app/style.css>; importance=high
Link: </app/script.js>; importance=low
fetchでも
<script>
 fetch('/api/articles.json', { importance: 'high' }).then(/*...*/)
 fetch('/api/related.json', { importance: 'low' }).then(/*...*/)
</script>

キャッシュがHitした情報を示すCacheヘッダの標準化提案

20191104 追記
draft 01でCache-Status に改称されるとともに、内容も変わりました
更新記事を書きました
asnokaze.hatenablog.com


CDNなどのサービスは、リクエストがキャッシュにヒットしたかどうかをx-cacheヘッダに格納してレスポンスしてくれます

このx-cacheヘッダは独自の形式であり、例えば以下のようになっています。
CDNによっては、x-cache以外のヘッダを使うものもあります)

fastly (document)

X-Cache: MISS, HIT

Amazon CloudFront

X-Cache: Hit from cloudfront

先述のように、x-cacheヘッダは標準化されておらずCDN毎に独自に使用されています。

そこで、IETFのHTTbisにおいて
キャッシュのHit情報などを格納するcacheヘッダの標準化を行う「The Cache HTTP Response Header」という仕様がFastlyのMark Nottingham氏から出されています。

Cacheヘッダ

Cache: HIT_FRESH; node="reverse-proxy.example.com:80";
                    key="https://example.com/foo|Accept-Encoding:gzip",
           HIT_STALE; node="FooCDN parent"; fresh=-45; age=200; latency=3,
           MISS; node="FooCDN edge"; fresh=-45; age=200; latency=98

(シンタックスについては 以前書いた「Structured Headersの記事」を参考に)

リクエストが複数回forwardされた場合は、レスポンスを返す順にカンマ区切りで情報が追記されていく。頭のほうがオリジンに近いほうで、後ろのほうがユーザエージェントに近い。

cache-actions

cache-actionsと呼ばれる、リクエストに対してどういうアクションを取ったかは以下の種類がある

  • HIT_FRESH: リクエストをforwardすることなく、キャッシュとして期限内(fresh)であるものを返した
  • HIT_STALE: リクエストをforwardすることなく、キャッシュとして期限内(fresh)ではないものを返した
  • HIT_REFRESH_MODIFIED: キャッシュが有効ではなかったので、リクエストをforwardして新しく得られたレスポンスを返した
  • HIT_REFRESH_NOT_MODIFIED: キャッシュが有効ではなかったので、リクエストをforwardして有効性が確認できたキャッシュしていたレスポンスを返した
  • HIT_REFRESH_STALE: キャッシュが有効ではなかったので、リクエストをforwardしたが問題が発生したため、保存してあったキャッシュを返した
  • MISS: キャッシュが無かったためリクエストをforwardした
  • MISS_CLIENT: リクエスにCache-Controlヘッダのような、キャッシュが使えないようなパラメータが含まれていたので、リクエストをforwardした
  • BYPASS: レスポンスをキャッシュするように設定されていない
  • ERROR: 保存してあったものか、forwardして得られたキャッシュが使用できなかった
パラメータ

各アクションは下記パラメータを付けることが出来る(OPTIONAL)

  • node: ホスト名やIPアドレスといった、キャッシュノードの識別子
  • fresh: freshさの有効期限([https://tools.ietf.org/html/rfc7234#section-4.2.1:title=[RFC7234], Section 4.2.1])。秒で示され、負の値を取ることも出来る。
  • age: このキャッシュの age を示す([https://tools.ietf.org/html/rfc7234#section-4.2.1:title=[RFC7234], Section 4.2.3])
  • cacheable: このレスポンスをキャッシュとして保存できるかのboolean値
  • key: キャッシュがレスポンスと関連付けられるキー
  • latency: リクエストを受け取ってからレスポンスを返すまでの遅延ミリ秒
  • cl_nm: クライアントへの応答に304 Not Modifiedが含まれるかを示す

DNS over HTTPSサーバを見つけるためのTXTレコードの提案仕様

20190821 追記
この提案は廃案されました
https://mailarchive.ietf.org/arch/msg/doh/qkmhh93Id6XIngH3LJwp-HokH_Y


DNS over HTTPS(DoH)の標準化が進められており、引き続き注目を集めている。
asnokaze.hatenablog.com

一方で、DoHサーバをどのように見つけるか、見に行かせるかの議論が始まっています。
JPNIC Blog :: DNS over HTTPSとDHCP -IETF102における議論- で紹介されている通り、先月行われたIETF102でもDNSゾルバの識別子と利用についてのBoFがありました。

例えば、設定ファイルだったり、DHCPDNSサーバを設定する際にDoHサーバを設定する際にどうすればいいか、どのようディスカバリさせるかといった議論です。

その流れで、DoH関連の標準化を推し進めているPaul Hoffman氏より「Associating a DoH Server with a Resolver」という提案仕様が出ています。

この手提案仕様では、主なユースケースとして名前解決をDoHに切り替えたいブラウザとしており、その次としてOSとしています。

Associating a DoH Server with a Resolver

この仕様では、resolver-associated-doh.arpa に対してTXTレコードを引くことで、そのリゾルバと関連付けられているDoHサーバのURIを取得できるようにします。

この仕組を解釈するリゾルバは、問い合わせに対してもし関連付けられているDoHサーバがあればそのURI (例 "https://dnsserver.example.net/dns-query{?dns}" )を返し、なければ0x00を返します。

おそらくこんな感じ

;; ANSWER SECTION:
resolver-associated-doh.arpa.  600  IN  TXT  "https://example.com/dns-query{?dns}"

DoHサーバを利用する場合は、レスポンスのTTL時間の間だけ使用されることが推奨されています(SHOULD)。

resolver-associated-doh.arpaは「Special-Use Domain Names」として予約されることになります。

Loading Signed Exchangesの仕様 (WebPackaging)

WebPackagingと呼ばれる仕組みが議論されているのは、以前このブログでも紹介したとおりである。
asnokaze.hatenablog.com

この仕組みは3つの仕様からなる。

署名されたHTTP Exchangesをユーザエージェントがどのように読み込むかを定義したLoadingの仕様ですが、
、他のものにくらべ少々遅くなったが、「Loading Signed Exchanges」としてリポジトリに追加されていたので簡単に目を通す。

が、Fetch力が高くないので詳しい人に補足頂ければ幸いだ。

Loading Signed Exchanges

僕なりの理解としては、大まかなLodingの流れは以下の通り。

Signed HTTP Exchangesの一形式であるsxgファイルを https://distributor.example.org/foo.sxg から読み込んで、署名されているhttps://publisher.example.org/foo からのHTTPレスポンスを読み込む例を示す。

f:id:ASnoKaze:20180824015818p:plain

  • ユーザエージェントがhttps://distributor.example.org/foo.sxgをフェッチする
  • 取得したfoo.sxgのMIME Typeがapplication/signed-exchangeであることを確認し、signed exchangesをパースし、証明書や署名や有効期限などもろもろの確認を行う。
  • もともとのリクエストを https://publisher.example.org/foo にリダイレクトする (通常通りのリダイレクト)
  • そのリダイレクトが signed exchanges に含まれるリクエストとマッチすることを確認
  • signed exchangesからレスポンスを得る

具体的には、Fetchの使用に対してMonkey Patchを当てるとともに、公開鍵や署名といったValidationのアルゴリズムを定義している。またService Workerでの扱いについても言及している。

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

2021/01/30 追記:RFC8959で標準化されました
https://www.rfc-editor.org/rfc/rfc8959.html


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

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

先日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 ヘッダの提案

20190424 追記
IETFに提案仕様が提出されました
https://tools.ietf.org/html/draft-west-http-state-tokens-00


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ハンドシェイク (ssl_early_data)を試す

追記20180922
OpenSSLも対応しました
「support for TLSv1.3 early data with OpenSSL.」
http://hg.nginx.org/nginx/rev/548a63b354a2


昨日、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