2016/11/22

Node.js + Express4でSSL/TSL通信をする方法

フロントエンドをHTTPS化対応したとき、サーバサイドの対応を忘れて以下のようなエラーが表示され、APIを実行できなかった。

Mixed Content: The page at 'https://xxx.xxx.xxx.xxx/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://xxx.xxx.xxx.xxx/'. This request has been blocked; the content must be served over HTTPS.
XMLHttpRequest cannot load http://xxx.xxx.xxx.xxx/. Failed to start loading.

httpsとhttpが混在してるよ。ページはhttpsで読み込まれてるけど、そこからhttpへリクエストしようとしてるからブロックしといた。やるならhttps経由でやってくれ。という内容。

ということで、Node.js + Express4で開発していたサーバサイドをhttps化してSSL/TSL通信できるようにしたので、その対応方法をまとめる。



アプリのディレクトリ構成


以下のディレクトリ構成を前提として、説明をしていく。
.
├── keys
│   ├── server.key    // <-- 秘密鍵
│   └── server.crt    // <-- サーバ証明書
├── package.json
└── app.js

// package.json
{
  "name": "express4-sample",
    "start": "node app.js"
  },
  "main": "app.js",
  "dependencies": {
    "body-parser": "^1.15.2",
    "express": "^4.13.3"
  }
}



オレオレ証明書の作成


本来なら認証局(VeriSignやLet'sEncryptyなど)が発行した証明書を使ったほうが良いのだが、実験なのでオレオレ証明書(自己証明書)を使う。
cd keys

# Create private key
openssl genrsa 2048 > server.key
# Create certificate signing request
openssl req -new -key server.key > server.csr
# Create server certificate
openssl x509 -in server.csr -days 30 -req -signkey server.key > server.crt

詳細については、以下の記事の「オレオレ証明書(自己証明書)の作成」の章を参考にしてほしい。


アプリケーションの作成


// app.js
const express = require('express');
const bodyParser = require('body-parser');
const https = require('https');
const fs = require('fs');
const app = express();

const sslOptions = {
  key: fs.readFileSync('../keys/server.key'),
  cert: fs.readFileSync('../keys/server.crt')
};

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

const port = process.env.PORT || 3000;
const router = express.Router();

router.get('/', (req, res) => {
  res.send('response message');
});

app.use('/', router);

https.createServer(sslOptions, app).listen(port);


Express4でSSL/TSL通信をするためには、25行目のhttps.createServer({ key: 秘密鍵, cert: サーバ証明書 }, app).listen(port);をするだけでよい。
サンプルコード上では、可読性を考慮してsslOptionsという変数に秘密鍵/サーバ証明書のセットを入れて使っている。

ちなみにbodyParser関連については、https化には直接関係ないがPOSTパラメータを受け取るために必要な処理だ。



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿