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.Server
の newSession
と resumeSession
というイベントが定義されているので、これを使ってセッション情報の管理をおこないます。
以下はサンプルコードです。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.Server
も tls.Server
を継承しているので、httpsモジュールでも同様の処理をおこなうことができます。また、複数のサーバーでSSLのセッションキャッシュを共有する必要があるような場合には、memcachedやRedisをセッションキャッシュサーバーとして用意しておき、そこにセッション情報を保存する必要があることに注意してください。
SSLには、セッションチケットと呼ばれるクライアント側に情報をキャッシュさせる拡張も用意されています。セッションチケットを含む、SSLセッションキャッシュのより詳しい情報は以下のページにまとめられているので、こちらもオススメです。