この記事は、HTTP2 Advent Calendar 2014 – Qiitaの10日目の記事です。

本来は、HTTP/2のセキュリティについていろいろ語ってみたかったのですが、HTTP/2を学習したり、実装する時間が確保できなかったため、HTTP/2をちょっと触ってみた感じになっています。いままで、HTTP/2という言葉を聞いたり見たことはあったのですが、実際に触ったことはありませんでした。

HTTP/2について

HTTP/2は、GoogleのSPDYをベースに、今までのHTTP/1.1での経験をもとに、通信の簡略化や表示の高速化などを測った次世代のHTTPプロトコルです。
具体的には、単独のストリームで複数のデータを送受信できたりすることが可能だったり、HPACKと呼ばれるヘッダ圧縮の仕様などもHTTP/2と一緒に策定されています。さらに、HTTP/1系ではテキストベースでしたが、HTTP/2はバイナリベースなこともあり、今までよりHTTPヘッダなどでのオーバーヘッドが少なくなり、効率のよい通信が行えるようになっています。

HTTP/1系の時にはtelnetとかでクライアントとしてHTTPサーバと通信して遊んだりしていましたが、そんなことができなくなりますね…

HTTP/2の仕様について

HTTP/2はIETFによりdraft-14でラストコールされましたが、今のところdraft-16まで確認できます。
draft-14の仕様 https://tools.ietf.org/html/draft-ietf-httpbis-http2-14
draft-14の日本語訳 http://summerwind.jp/docs/draft-ietf-httpbis-http2-14/

HTTP/2はHTTP/1.1との完全な後方互換性を持つ設計をするように定められていますが、どちらかと言うとネゴシエーションの際にHTTP/2に対応しているかのチェックが行われ、対応していない場合はHTTP/1.1として通信を行う感じで、HTTP/2のプロトコル自体は互換性がないです(あってないかも…)。

このへんのスライドが分かりやすかったです。

HTTP/2の実装について

HTTP/2の実装はいくつか公開されています。
サーバの実装では nghttp2 をよく目にします。
nghttp2をmac osx でビルドしたいを参考にすると結構簡単にビルドできます。

クライアントの実装ではChrome Canaryが有名です、Chrome Canaryの起動時に以下のオプションを付けることによって、HTTP/2を扱うことができます。

/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --enable-spdy4

HTTP/2はHTTP/1.1と同じくTCPの上とTLSののプロトコルであり、HTTP/2は識別子として、HTTP/2 over TCPをh2cと言ったり、HTTP/2 over TLSをh2と言ったりするそうです。しかし、ドラフト版ではこれらの識別子にドラフトのバージョンを負荷しなければならず、HTTP/2 over TLSのdraft-14であればh2-14という識別子が使われます。

Chrome Canayでは今のところh2-14を扱うことができますが、h2c(平文でのHTTP/2)に対応していないため、デバッグなどではnghttp2のクライアントを使ったほうが便利かもしれません。

HTTP/2の実装を作ってみたかった…

セキュリティについてかけなさそうだったのなにか実装をしてみようと思い、今あるサーバの実装に対応できるクライアントの実装を作ってみたのですが、nghttp2を対象にしたら以下のコードだけで受信できてしましました…
本来、俗に謎の文字列と呼ばれるPRISMを送らないといけないはず……?


ついでに、nghttp2のクライアントからHTTP/2に対応した http://nghttp2.org/ に接続してみた時のWiresharkをみてみます。

  1. まずはじめにHTTP/1.1でリクエストを飛ばします。h2であればALPN(Protocol Negotiation)で、h2cであればHTTP/1.1リクエストのUpgradeヘッダで、HTTP/2を扱えることを宣言します。ALPNはspdyなどで使われてますし、Upgradeもwebsocketなどで使われていますね。
    Screenshot 2014-12-10 18.47.37

  2. http://nghttp2.org/のサーバはHTTP/2に対応しているため、Switching Protocolと返し、その後HTTP/2の通信が行われます。
    最初に述べたとおり、HTTP/2はHTTP/1.1と互換性を持っているため、HTTP/2が扱えないサーバではこの後HTTP/1.1の通信が行われます。
    Screenshot 2014-12-10 18.43.55

  3. サーバからSETTINGSフレーム(type=0x4)が送られてきます。
    Screenshot 2014-12-10 18.44.10

  4. その後、サーバからHEADERSフレーム(type=0x1)が送られ、DATAフレーム(type=0x0)が送られてきます。
    Screenshot 2014-12-10 18.44.23

ちなみに、今のところOS Xの最新のWiresharkではdraft-13までしか対応しておらず、FrameのPayload Lengthのビット長が違かったりするので、ちゃんと解析してくれません。
Screenshot 2014-12-10 7.46.59

おわりに

本当はセキュリティの話をしたかったのですが、なんとなく仕様とか実装とかの話になってしまいました。
ちなみに、セキュリティについてはHTTP/2の仕様の10章で書かれています。HTTP/2の複数データをやりとりする際の注意とかリソース消費によるDoSとか…

HTTP/2では、アプリケーションに影響が内容設計されたのでWebアプリケーションのSQLiやXSS、CSRFがどうなるといったことはないです。
ただ、1つ気になるのが、HPACKの仕様ではヘッダがすべて小文字となっていますが、HTTPヘッダでカスタムヘッダを付加しているアプリケーションについての挙動は大丈夫なのか心配です。

HTTP/2がバイナリになってちょっとおもしろくなってきそうですね。