古いバージョンの Node.js で2021年10月からhttps通信が失敗する問題対応

投稿日: 2021/10/20 17:17

当社ではWebからデータを取得したりアップしたりする自作ツールにNode.js(Javascriptで色々なプログラムを作れる奴)を使っているのですが、
今年の10月になってからなぜか「Certificate has expired」というエラーが出て通信に失敗する問題が発生していました。

Google先生にお伺いを立てたところ、どうやらhttpsのルート証明書関連の問題とのこと。
当社でも使っている、httpsの証明書を無料で発行してくれる Let’s Encrypt が独自の証明書に移行し、古い証明書が10月1日で失効したために期限切れというエラーが出ているよう。
相手先のWebサーバがLet’s Encryptの証明書でhttps化を行っており、こっちのNode.jsが古いと発生する模様。
Node.js以外にも、古いOSや組み込みデバイスでも同じ問題を抱えているとの事。

https://news.mynavi.jp/article/20211004-1991195/

結構解決に苦労したため、やり方を忘れないためにここに記載しておきます。

当社で使っているツールのNode.jsのバージョンはv8、Webの情報によればv12までは同様の問題を抱えているようで、v14以降にアップデートすれば解決する模様。
残念ながら当社の自作ツールは前に作ってそのまま使っている乱雑な設計で、v10に上げた時点で動かなくなってしまう問題児であるためこの解決策は利用できず。
どうも調べたところ、Node.jsはOSのルート証明書を使うのではなく、Node.js独自のルート証明書リストを使っているらしい、しかもその証明書リストはNode.jsのバイナリにC言語でハードコーディングされてるようで利用者側から書き換えは難しそう。

続いて試した方法はv6以降のNode.jsで、「NODE_EXTRA_CA_CERTS」という環境変数を設定してNode.jsを起動することで追加のルート証明書を足せるというもの。
しかし、それらしいルート証明書を何個か足してみたものの、上手く動作せず。
検索した結果からの推測では「DST Root CA X3」という証明書が失効したことによる問題のようなので、既にあるルート証明書から該当する証明書を削除しなければダメなのではと考えている。

さらに検索を続けたところ、「NODE_OPTIONS」環境変数に –use-openssl-ca を設定することでopensslのルート証明書を使うことができるらしいという情報が。

https://nodejs.org/api/cli.html#–use-bundled-ca—use-openssl-ca

結果的にこれで動作したのですが、 –use-openssl-ca オプション単品ではどこにルート証明書を探しに行っているのかよくわからず、↑のNode.jsのマニュアルにあった、「SSL_CERT_FILE」環境変数にルート証明書のファイルを指定する方法を採用。
こちらのオプションはルート証明書の追加ではなく、まるっと入れ替えてくれるよう。(設定ミスると証明書が無いぞと怒られた)
どこかからルート証明書の塊を取得しなくてはいけないため、curlコマンドラインのページにMozillaのルート証明書らしきものを見つけたためそれを利用。

https://curl.se/docs/caextract.html

取得したpemファイルには120超のルート証明書が入っているようなので、そのファイルを適当な場所において、SSL_CERT_FILE環境変数に設定。
これでLets Encryptの証明書使っているWebサイト相手でもhttps通信が通るようになりました。

忘れないように今回やったことの一覧。

  • NODE_OPTIONS=”–use-openssl-ca” 環境変数を設定
  • SSL_CERT_FILE=”C:/****/cacert.pem” 環境変数を設定
  • Windows10 Node.js v8.17.0