node.js でWebスクレイピングするツールを作ったのですが、アクセス先のサイトの証明書が切れたらしく最近更新されたようです。それは問題ないのですが、なぜか中間CA証明書が返ってこず(たぶんWebサーバーの設定漏れ)、証明書の検証ができない旨のエラーが。wget してみても同様の状態。証明書チェーンの検証を無効にすればつながりますが、セキュリティ的によろしくないです。まあ、管理者に連絡して設定してもらえばいいんですが、それまで待っていられない場合の応急処置を書いておきます。
ちなみに中間証明書をWebサーバーに設定していなくても、モダンなブラウザは勝手にダウンロード(またはキャッシュ?)してくれるっぽいので、ページは通常通り表示されます。おそらく OpenSSL 使う系が検証できなくなる模様。
環境は CentOS 6 または Windows と node.js 8 です。
node では以下のような例外が投げられます。
{ Error: unable to verify the first certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1047:34)
at TLSSocket.emit (events.js:182:13)
at TLSSocket._finishInit (_tls_wrap.js:629:8) code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' }
中間証明書が設定されているか
まずは原因切り分け。接続先の Web サーバーが悪いのか確認します。証明書発行してくれるところが便利な Webサイトを用意してくれているので、それらを使います。ここでは DigiCert さんのを使わせていただきます。
https://ssltools.digicert.com/checker/views/checkInstallation.jsp
Check Website Security | DigiCert SSLTools
中間証明書が設定されていない場合、「Intermediate certificate missing」と出ます。サーバーの証明書が DigiCert から発行されたものの場合は、中間証明書のダウンロードリンクが出てきます。
中間証明書が設定されていないサイトを wget すると以下のように出力されます。
[root@hostname anchors]# wget https://example.com -O -
--2019-01-26 00:00:00-- https://example.com/
example.com をDNSに問いあわせています... xxx.xxx.xxx.xxx
example.com|xxx.xxx.xxx.xxx|:443 に接続しています... 接続しました。
エラー: example.com の証明書(発行者: `XXXX')の検証に失敗しました:
発行者の権限を検証できませんでした。
example.com に安全の確認をしないで接続するには、`--no-check-certificate' を使ってください。
中間証明書のダウンロード
ブラウザで対象のサイトを表示し、証明書を表示すると中間証明書が出るはずです。保存の方法はこの問題の本筋ではないので割愛します。以下のようなやつが手に入れば問題なしです。できるだけ信頼できる方法で入手しましょう。
-----BEGIN CERTIFICATE-----
~~Base64形式の X.509~~
-----END CERTIFICATE-----
クライアント側に中間証明書を置く(CentOS)
Windows の場合は下に記載しました。
/etc/pki/ca-trust/source/anchors/
ディレクトリ内に、 foo.pem
など任意の名前で証明書を保存します。
次に update-ca-trust extract
で設定を反映させます。CentOS 6 ではデフォルトで無効になっているので、 update-ca-trust enable
を実行します。有効かは update-ca-trust check
で確認できます
この時点で wget は成功するようになっているはずです。
node.js に反映
上記で設定した証明書は最終的に /etc/pki/tls/certs/ca-bundle.crt
に反映されるようです。中身は上記のような証明書が列挙されています。このファイルを環境変数 NODE_EXTRA_CA_CERTS に設定してあげれば問題は解消するはずです。指定方法は以下のようにします。
exports NODE_EXTRA_CA_CERTS=/etc/pki/tls/certs/ca-bundle.crt
NODE_EXTRA_CA_CERTS=/etc/pki/tls/certs/ca-bundle.crt node main.js
Windows の場合
そもそもなのですが、node.js だけ問題を解消したいなら update-ca-trust
を使用しなくても大丈夫です。落としてきた中間証明書を環境変数に設定してあげるだけです。
$env:NODE_EXTRA_CA_CERTS = ".\xxxx.cer"
node main.js
set NODE_EXTRA_CA_CERTS=.\xxxx.cer
node main.js