Node.js + Express で作るウェブアプリケーションを HTTPS 対応し、更に「HTTPS 以外の通信を認めない」ように設定してみます。なお SSL 対応用のドメイン取得や証明書の取得は完了しているものとし、ドメインは mydomain.com 、秘密鍵ファイルと証明書ファイルがそれぞれ、
・/etc/letsencrypt/live/mydomain.com/privkey.pem (秘密鍵)
・/etc/letsencrypt/live/mydomain.com/cert.pem (証明書)
に存在しているものと仮定して以下を説明します。
【Node.js + Express で HTTPS 通信】
Node.js + Express で HTTPS 通信を行うには https モジュールを利用します:
https モジュールを使って 8443 番ポートで待ち受ける https サーバーを作ります。その際に秘密鍵や証明書を指定することで SSL 通信を行うことができるようにしています。
このファイルを Node.js で実行して、ウェブブラウザや curl コマンドで https://mydomain.com:8443/hello にアクセスすることで動作を確認することができます(curl コマンドで localhost など、異なるドメインにアクセスする場合は $ curl https://localhost:8443/hello --insecure といった具合に --insecure オプションを付けて実行することで確認できます)。
また、上記の方法だと https のみアクセスできます(http だと接続エラー)が、http / https 両方でのアクセスに対応するには以下のように改良します:
これを実行すると、http を 8080 番ポートで、https を 8443 番ポートで同時に待受けてレスポンスを返すことができるようになりました。ウェブブラウザや curl コマンドで http://mydomain.com:8080/hello や https://mydomain.com:8443/hello にアクセスして挙動を確認してください。
【HTTP 通信をしない(HTTPS へ転送)】
最後に、上記プログラムを更に改良して HTTP 通信をしない(強制的に HTTPS 通信に転送する)ための設定を加えます。それには Strict-Transport-Security ヘッダを付けてレスポンスを返すことで実現できます:
HSTS(HTTP Strict Transport Security) という仕組みを強制することで HTTP でリクエストを受け取っても HTTPS に強制的に変更(リダイレクト)されて通信を続ける、というものです。リダイレクトさせるには HTTP そのものを閉じるわけにはいかない(リダイレクト直前のリクエストを受け取らないといけない)ので、このようなレスポンスヘッダによって実現しています:
【参考】
良い感じにHTTPS対応したexpress(Node.js)サーバを立てる
node.jsによるHTTPSサーバの作り方
・/etc/letsencrypt/live/mydomain.com/privkey.pem (秘密鍵)
・/etc/letsencrypt/live/mydomain.com/cert.pem (証明書)
に存在しているものと仮定して以下を説明します。
【Node.js + Express で HTTPS 通信】
Node.js + Express で HTTPS 通信を行うには https モジュールを利用します:
var express = require( 'express' ); var app = express(); var fs = require( 'fs' ); var https = require( 'https' ); var options = { key: fs.readFileSync( "/etc/letsencrypt/live/mydomain.com/privkey.pem" ), cert: fs.readFileSync( "/etc/letsencrypt/live/mydomain.com/cert.pem" ) }; var https_server = https.createServer( options, app ); app.get( '/hello', function( req, res ){ res.contentType( "text/plain" ); res.writeHead( 200 ); res.end( "Hello World." ); }); var https_port = 8443; https_server.listen( https_port ); console.log( "server starging on " + https_port + ' ...' );
https モジュールを使って 8443 番ポートで待ち受ける https サーバーを作ります。その際に秘密鍵や証明書を指定することで SSL 通信を行うことができるようにしています。
このファイルを Node.js で実行して、ウェブブラウザや curl コマンドで https://mydomain.com:8443/hello にアクセスすることで動作を確認することができます(curl コマンドで localhost など、異なるドメインにアクセスする場合は $ curl https://localhost:8443/hello --insecure といった具合に --insecure オプションを付けて実行することで確認できます)。
また、上記の方法だと https のみアクセスできます(http だと接続エラー)が、http / https 両方でのアクセスに対応するには以下のように改良します:
var express = require( 'express' ); var app = express(); var settings = require( './settings' ); var fs = require( 'fs' ); var http = require( 'http' ); var https = require( 'https' ); var options = { key: fs.readFileSync( "/etc/letsencrypt/live/mydomain.com/privkey.pem" ), cert: fs.readFileSync( "/etc/letsencrypt/live/mydomain.com/cert.pem" ) }; var https_server = https.createServer( options, app ); var http_server = http.createServer( app ); app.get( '/hello', function( req, res ){ res.contentType( "text/plain" ); res.writeHead( 200 ); res.end( "Hello World." ); }); var http_port = 8080; var https_port = 8443; https_server.listen( https_port ); http_server.listen( http_port ); console.log( "server starging on " + http_port + ' / ' + https_port + ' ...' );
これを実行すると、http を 8080 番ポートで、https を 8443 番ポートで同時に待受けてレスポンスを返すことができるようになりました。ウェブブラウザや curl コマンドで http://mydomain.com:8080/hello や https://mydomain.com:8443/hello にアクセスして挙動を確認してください。
【HTTP 通信をしない(HTTPS へ転送)】
最後に、上記プログラムを更に改良して HTTP 通信をしない(強制的に HTTPS 通信に転送する)ための設定を加えます。それには Strict-Transport-Security ヘッダを付けてレスポンスを返すことで実現できます:
var express = require( 'express' );
var app = express();
var settings = require( './settings' );
var fs = require( 'fs' );
var http = require( 'http' );
var https = require( 'https' );
var options = {
key: fs.readFileSync( "/etc/letsencrypt/live/mydomain.com/privkey.pem" ),
cert: fs.readFileSync( "/etc/letsencrypt/live/mydomain.com/cert.pem" )
};
var https_server = https.createServer( options, app );
var http_server = http.createServer( app );
//add HSTS
app.use( function( req, res, next ){
res.setHeader( 'Strict-Transport-Security', 'max-age=15552000' );
next();
});
app.get( '/hello', function( req, res ){
res.contentType( "text/plain" );
res.writeHead( 200 );
res.end( "Hello World." );
});
var http_port = 8080;
var https_port = 8443;
https_server.listen( https_port );
http_server.listen( http_port );
console.log( "server starging on " + http_port + ' / ' + https_port + ' ...' );
HSTS(HTTP Strict Transport Security) という仕組みを強制することで HTTP でリクエストを受け取っても HTTPS に強制的に変更(リダイレクト)されて通信を続ける、というものです。リダイレクトさせるには HTTP そのものを閉じるわけにはいかない(リダイレクト直前のリクエストを受け取らないといけない)ので、このようなレスポンスヘッダによって実現しています:
【参考】
良い感じにHTTPS対応したexpress(Node.js)サーバを立てる
node.jsによるHTTPSサーバの作り方