SummerWind

Web, Photography, Space Development

Node.jsでSSLセッションキャッシュを使う

最近、WebにおいてはSSL通信を使うのが当たり前になりつつあるように思います。Googleの検索は全てSSLになりましたし、スマホアプリがAPIサーバーと通信する場合もSSLを使っているなんてことも多いかと思います。SSLを使うことで通信がセキュアになるメリットが得られますが、SSL通信を開始するためにはSSLハンドシェイクをおこなう必要があるので、その分レイテンシが大きくなるデメリットもあります。

HTTP/2.0ではこのようなレイテンシを小さくするために、接続を可能な限り維持する方向で仕様の策定が進んでいます。既存のHTTPSでもSSLのレイヤーで少しでもレイテンシを削減する方法はないものか、としばらく考えていたのですが、SSLセッションキャッシュというものがあることを知ったので少し使ってみました。

SSLセッションキャッシュ

SSLのセッションが開始される際には、SSLハンドシェイクがおこなわれます。ハンドシェイクでは証明書による認証や鍵の交換がおこなわれるわけですが、この処理にコストがかかるため、SSLの開始に時間がかかる原因になっています。

SSLセッションキャッシュは、1度おこなったハンドシェイクの情報をキャッシュしておくことで、2回目以降のハンドシェイクを簡略化するための機能です。この機能を使うことで、例えばHTTPSで複数のリソースを取得する必要があるような場面において、2つめ以降のリソース取得時のSSLハンドシェイクを簡略化して、レイテンシを小さくすることができます。

Node.jsにおけるSSLセッションキャッシュ

Node.jsでは、v0.9.2からSSLセッションキャッシュを使うことができるようになりました。tls.ServernewSessionresumeSession というイベントが定義されているので、これを使ってセッション情報の管理をおこないます。

以下はサンプルコードです。newSession イベントでセッション情報を保存し、resumeSession イベントでセッション情報が存在すればそれを返す、というコードになっています。

var tls = require('tls'),
    fs  = require('fs');

var session_store = {};

var options = {
  key: fs.readFileSync('./key.pem'),
  cert: fs.readFileSync('./cert.pem')
};

var server = tls.createServer(options);

// セッション情報を保存
server.on('newSession', function(id, data) {
  session_store[id] = data;
  console.log('New Session!');
});

// セッション情報を再利用
server.on('resumeSession', function(id, cb) {
  cb(null, session_store[id] || null);
  console.log('Reused Session!');
});

server.listen(4433);

以下のように、サンプルコードを実行し、OpenSSLのコマンドからサーバーにアクセスすると、セッション情報が再利用されていることを確認することができます。

$ node server.js &
$ openssl s_client -reconnect -host localhost -port 4433 2>&1 | grep -e "\(Reuse\|New\)"
New, TLSv1/SSLv3, Cipher is AES256-SHA
Reused, TLSv1/SSLv3, Cipher is AES256-SHA
Reused, TLSv1/SSLv3, Cipher is AES256-SHA
Reused, TLSv1/SSLv3, Cipher is AES256-SHA
Reused, TLSv1/SSLv3, Cipher is AES256-SHA
Reused, TLSv1/SSLv3, Cipher is AES256-SHA

今回のサンプルコードはtlsモジュールを使用したものになっていますが、https.Servertls.Server を継承しているので、httpsモジュールでも同様の処理をおこなうことができます。また、複数のサーバーでSSLのセッションキャッシュを共有する必要があるような場合には、memcachedやRedisをセッションキャッシュサーバーとして用意しておき、そこにセッション情報を保存する必要があることに注意してください。

SSLには、セッションチケットと呼ばれるクライアント側に情報をキャッシュさせる拡張も用意されています。セッションチケットを含む、SSLセッションキャッシュのより詳しい情報は以下のページにまとめられているので、こちらもオススメです。

Moto Ishizawa

Moto Ishizawa
ソフトウェアエンジニア。ロケットの打上げを見学するために、たびたびフロリダや種子島にでかけるなど、宇宙開発分野のファンでもある。