mkcert 証明書を用いてローカル環境で Secure Contexts(HTTPS)

Web Bluetooth や WebNFC, MediaDevices などウェブブラウザだけで実現できることが増えてきて便利になった反面、そうした機能を用いるために Secure Contexts(HTTPS)が要求される機会も増えました。

外部に公開されているウェブサーバであれば、いずれにせよ証明書の取得や更新、設定が必要となるので気にすることもないですが、ローカル開発環境で検証する際には鬱陶しいと思うこともしばしば。

そこで https モデュールと mkcert 証明書を用いてローカル環境で擬似的に通信の暗号化をすることを考えます。

実行環境は Linux (Ubuntu) です。

$ uname -rvpo
5.15.0-50-generic #56-Ubuntu SMP Tue Sep 20 13:23:26 UTC 2022 x86_64 GNU/Linux

$ cat /etc/os-release |grep -i version
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"

$ apt --version
apt 2.4.8 (amd64)

$ npm --version
8.5.1

$ node --version
v12.22.9

$ express --version
4.16.1

まずはアプリケーションを作成して必要なモデュールを用意します。

$ express --view=pug myapp
$ cd myapp 

$ npm i fs https
$ tail -n 11 package.json 
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "fs": "^0.0.1-security",
    "http-errors": "~1.6.3",
    "https": "^1.0.0",
    "morgan": "~1.9.1",
    "pug": "2.0.0-beta11"
  }
}

アプリケーションの準備が整ったら、次に mkcert をインストールします。
単体でインストールすると Firefox と Chrome/Chromium ブラウザに証明書を自動的に導入できないという警告文が表示されるので libnss3-tools も一緒に導入したほうが簡潔です。

$ sudo apt install -y mkcert 
$ which mkcert
/usr/bin/mkcert

$ mkcert --version
1.4.3

$ sudo mkcert -install
The local CA is now installed in the system trust store! ⚡️
Warning: "certutil" is not available, so the CA can't be automatically installed in Firefox and/or Chrome/Chromium! ⚠️
Install "certutil" with "apt install libnss3-tools" and re-run "mkcert -install" ?

$ sudo apt install -y libnss3-tools

導入後に次のコマンドを実行するとローカル認証局 Certificate Authority (CA) が作成されます。

$ sudo mkcert -install
Created a new local CA ?
The local CA is now installed in the system trust store! ⚡️

これはサーバに対して証明書を発行するローカル認証局 (CA) です。作成される場所はカレントディレクトリではなく -CAROOT オプションで表示されるパスです。

$ mkcert -CAROOT
/home/Galjoen/.local/share/mkcert

これで証明書を発行できるようになりましたので、任意のディレクトリに証明書を作成します。

$ mkdir ssl;cd ssl 
$ mkcert example.com "*.example.com" localhost 127.0.0.1 ::3000 

Created a new certificate valid for the following names ?
 - "example.com"
 - "*.example.com"
 - "localhost"
 - "127.0.0.1"
 - "::3000"

Reminder: X.509 wildcards only go one level deep, so this won't match a.b.example.com ℹ️

The certificate is at "./example.com+3.pem" and the key at "./example.com+3-key.pem" ✅

It will expire on 8 January 2025 ?

$ ls -a 
example.com+3-key.pem example.com+3.pem

証明書ファイルが作成されましたのでアプリケーションのサーバから、これらを読み込みます。

Express アプリケーションのスタートアップスクリプトは bin/www ファイルなので、これに編集を加えます。

$ cd .. 
$ vi bin/www
#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('attendanceapp:server');
// var http = require('http');

// create HTTPS server instead HTTP 
const https = require('https');
const path = require('path');
const fs = require('fs');
const ssl_server_key = path.resolve(__dirname, `../ssl/example.com+3-key.pem`);
const ssl_server_crt = path.resolve(__dirname, `../ssl/example.com+3.pem`);
const options = {
  key: fs.readFileSync(ssl_server_key),
  cert: fs.readFileSync(ssl_server_crt)
};

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

//var server = http.createServer(app);
const server = https.createServer(options, app);

これで準備完了なのでアプリケーションを起動して、ウェブブラウザを用いて動作確認を行います。

$ npm start &
$ curl https://localhost:3000 --insecure | head -c 50 
Express<

ここまで設定しても"NET::ERR_CERT_AUTHORITY_INVALID" の警告文が表示される場合、ウェブブラウザを再起動すると証明書が読み込まれて解決する場合があります。

Leave a Reply

Your email address will not be published. Required fields are marked *