Thursday, July 23, 2015

前方秘匿性 (forward secrecy) をもつウェブサイトの正しい設定方法

前方秘匿性(forward secrecy)とは、以下のような性質を指します。

公開鍵暗号の秘密鍵のように、比較的長期に渡って使われる鍵が漏えいしたときでも、それまで通信していた暗号文が解読されないという性質
鍵が漏れることも想定せよ――クラウド時代における「楕円曲線暗号」の必然性 - @IT

鍵が攻撃者や諜報機関など第三者の知るところとなった場合でも、それまで通信していた暗号文が解読されないようにしないといけない、という考え方とともに、最近 HTTPS を利用するウェブサイトにおいても導入が求められるようになってきた概念です。

前方秘匿性を満たすウェブサイトの設定方法については、TLSの暗号化方式をECDH_RSAあるいはECDHE_RSAに設定すれば良い、と述べている文献が多いです。

ですが、ほとんどのウェブサーバにおいて、それは誤りです。

なぜか。

通信を暗号化する鍵(セッション鍵)の確立にDHEあるいはECDHEを用いれば前方秘匿性が確保されるというのは、鍵交換に議論を限ってしまえば正しいです。

しかし、TLSプロトコルには、鍵交換以外にセッション鍵を保存し、再利用する仕組みが存在します。Session ResumptionとSession Ticketの2つがそれに該当します。

このうち、OpenSSLが標準でサポートし、ウェブブラウザが対応している場合(IE9以前とMobile Safari以外の全ての主要ウェブブラウザが該当します)にSession Resumptionより優先して利用されるSession Ticketは、セッション鍵をサーバのみが知るマスターキーで暗号化して、クライアントに送信します。

セッション鍵をマスターキーで暗号化…いやな響きがしませんか?

そうです。このSession Ticketの暗号化に使われるマスターキーを定期的に更新しない限り、マスターキーが流出してしまった場合、過去の通信内容がすべて解読されてしまうことになるのです。

しかし残念なことに、ほとんどのウェブサーバは、マスターキーを自動的に更新する仕組みをそなえていません

では、どのようにサーバを設定すればいいでしょうか。

解決策1. Session Ticket機能を無効化する

第一の解決策はウェブサーバの設定でSession Ticket機能を無効化することです。Apache の場合は SSLSessionTickets、nginx の場合は ssl_session_tickets という設定コマンドを使うことで、無効化することができます。

しかし、nginx (とevent mpmを使用するApache)は、複数サーバにまたがる session resumption 機能を実装していません。そのため、ロードバランサの背後に複数のHTTPSサーバを立てている場合は、session ticket をオフにすると、新規接続確立のたびにTLSハンドシェイクが発生し、ユーザの体感速度の低下やサーバの負荷増大につながってしまいます。

解決策2. サーバを定期的に再起動する

ApacheやNginxは、サーバを起動するタイミングで Session Ticket のマスターキーを再生成します。なので、たとえば1時間に1回サーバを再起動すれば、前方秘匿性を確保しつつ Session Ticket を使うことができます。簡単ですね!!!

なお、ロードバランサの背後に複数のHTTPSサーバを立てている場合は、それらのサーバを再起動する度に、新しいマスターキーが記述された設定ファイルを再配布する必要があります。このへんは Twitter さんの涙ぐましい努力の話があるので、それを参考にがんばりましょう。

解決策3. H2O を使う

これまで述べてきたように、これまでのウェブサーバの前方秘匿性のサポートはお粗末と言わざるをえません(他にも、マスターキーの強度が強力なセッションキーよりも弱いといった問題も存在します)。

そこで H2O ですよ!!!!

私たちが開発しているH2Oの最新バージョンは、これらの問題を全て解決しています。

具体的に言うと、

・Session Ticket のマスターキーは、他のサーバのように AES-128 ではなく AES-256 です
・Session Ticket は自動的に更新されます(デフォルト15分間隔)
・ロードバランサの背後に複数台のH2Oを設置する場合、Session Ticketをmemcachedで共有するように設定することが可能です
・ついでに、Memcached を用いた複数サーバにまたがるSession Resumptionにも対応しているので、Mobile Safari でのHTTPSアクセスも高速に処理することができます

というわけで、安全なウェブサイトを構築したい人は H2O 使えばいいんじゃないでしょうか。ちなみに、H2O 使うとユーザの体感速度も速くなるのでいいことづくめかと思います。

以上、ウェブサーバの設定に関する注意喚起、兼、H2Oの宣伝でした。

Wednesday, July 22, 2015

H2O version 1.4.0 released with outstanding support for forward secrecy and load balancing (and the experimental mruby handler)

Today I am happy to announce the release of the H2O HTTP/2 server version 1.4.0.

There have been a few changes and bug fixes from version 1.3.1 (that showed big performance improvements over the older generations of HTTP servers without support for request prioritization), but the most prominent ones are the following.

Support for the PROXY protocol

The PROXY protocol is a de-facto standard protocol used by L4 load balancers (such as AWS Elastic Load Balancing) to notify the web servers running behind them the IP addresses of the clients. Support for the protocol is essential for running a web server behind such load balancer; without the support it is impossible to log the address of the client or to work against attacks.

In version 1.4.0, we have added support for the protocol which makes H2O a good choice for large scale and/or highly-available web sites running multiple HTTP servers behind a load balancer.

Support for cache-based and ticket-based TLS session resumption using Memcached (and forward secrecy)

The PROXY protocol is not the only thing that now makes H2O a good choice for such websites.

When running a HTTPS server cluster behind a L4 load balancer, it is desirable that the server supports session resumption using a shared datastore such as memcached.

TLS Session Resumption: Full-speed and Secure is a good read for those who are interested in what session resumption is; in short, it reduces the time spent for establishing a TLS connection to about half, and also reduces the CPU time to below 10%!

However, until now, front-end HTTP servers have been not good at supporting session resumption using a shared datastore.

Among the two resumption methods, Nginx does not support the more-widely-deployed cache-based session resumption using a shared datastore.

It should also be noted that most web servers are not good at supporting ticket-based resumption; they use 128-bit AES for storing master secrets (even in cases when a more complex ciphersuite is used), and also do not automatically roll-over the secrets (which botches forward-secrecy).

As pointed out by Tim Taubert, the sad state of the server-side TLS session resumption implementations has been the headache of administrators trying to setup secure websites. Forward Secrecy at Twitter is an example that shows how difficult it is to configure a website supporting forward-secrecy.

Being the primary developer of H2O, I believe that web servers should be easily configurable to be secure; so in version 1.4.0 we have implemented the following features:

  • cache-based session resumption using memcached
  • automatic rollover of master secret used for ticket-based resumption
  • synchronization of master secrets that rollover, using memcached
  • directive to configure the cipher used for encrypting tickets (with default being aes-256-cbc)

Table 1.Supported Methods of Session Resumption
Resumption Method
Session ResumptionSession Ticket
Apache (prefork)yesno forward-secrecy (AES-128)
Apache (worker)yesno forward-secrecy (AES-128)
Apache (event)not sharableno forward-secrecy (AES-128)
Nginxnot sharableno forward-secrecy (AES-128)
Varnish (hitch)needs recompileno
H2Oyesyes (AES-256)

And with H2O, they are easy to use! A simple configuration like below activates all the features. The H2O server cluster will share information of both cache-based and ticket-based session resumption using memcached, with complex cipher used for protecting master secrets that are automatically rolled over.

listen:
  port: 443
  ssl:
    key-file: /path/to/key-file
    certificate-file: /path/to/certificate-file
  proxy-protocol: ON
ssl-session-resumption:
  method: all
  memcached:
    host: address.of.memcached.server
    port: 11211

Please refer to the documentation for the details of the configuration directive.

Experimental mruby Handler

We are also proud to announce that we now have a scripting engine running within the H2O standalone server that can be used to customize the behavior, and that the programming language is Ruby.

Developed by Yukihiro Matz (the father of the Ruby programming language) and others, mruby is an implementation of the language for embedded use. Thanks to MATSUMOTO Ryosuke the language runtime can now be used to script how the HTTP requests should be handled within H2O.

The handler is still in very early stages and considered unstable (therefore it is not turned on by default, you would need to pass -DWITH_MRUBY=ON as an argument to CMake to build H2O with support for the mruby handler), but nevertheless it is already a great addition to the H2O HTTP server; such a scripting engine gives you great flexibility to customize the behavior of the server depending on the tiny aspects of a HTTP request, or to mitigate attacks.

Please refer to Ryosuke's weblog for more information (in Japanese). In addition to topics related to H2O, you can find excellent entries about how to use a scripting engine within web servers to work against cyber attacks.

Conclusion

All in all, we are happy to provide a new release of the H2O server to the public, that is secure and easy to use (with flexibility), once again raising the bar of what people should expect on a HTTP server to provide.

I hope you enjoy using the new release of H2O.