node.jsでrequest-promiseを使用してHTTPリクエストを投げる際に証明書関連のエラーが出ることがあります。
エラーが出た際の対応方法です。
エラー内容
[2046-13-32T26:78:67.997] [ERROR] default - Error: certificate has expired
https://www.stock.future/market/price/rate_2076.csv
Error: Error: certificate has expired
https://www.stock.future/market/price/rate_2076.csv
    at rp.catch.err (/home/react/future/stock/lib/ImportFutureStockPrices.js:83542:7854)
    at tryCatcher (/home/react/future/stock/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/home/react/future/stock/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/home/react/future/stock/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/home/react/future/stock/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/home/react/future/stock/node_modules/bluebird/js/release/promise.js:690:18)
    at _drainQueueStep (/home/react/future/stock/node_modules/bluebird/js/release/async.js:138:12)
    at _drainQueue (/home/react/future/stock/node_modules/bluebird/js/release/async.js:131:9)
    at Async._drainQueues (/home/react/future/stock/node_modules/bluebird/js/release/async.js:147:5)
    at Immediate.Async.drainQueues (/home/react/future/stock/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:810:20)
    at tryOnImmediate (timers.js:768:5)
    at processImmediate [as _immediateCallback] (timers.js:745:5)
certificate has expired
これは「証明書の有効期限が切れている」という意味です。
しかし、有効期限内でも無効の証明書に対しても出ます。
エラー原因
下記のエラーが考えられます。
- 証明書の有効期限切れ
- 証明書チェーンが途切れた
- ルートCA証明書が更新されてない
ちょっと前に「Let’s Encrypt」でルートCA証明書の更新がありましたね。
古いバージョンのサーバでは更新されたルートCA証明書が入ってなくてエラーになっていました。
証明書の更新
SSLの証明書の有効期限が切れている場合は、証明書を更新しましょう。
CA証明書更新
ルートCA証明書が原因の場合はCA証明書を更新します。
# dnf search ca-certificates
================= 名前 完全一致: ca-certificates =================
ca-certificates.noarch : The Mozilla CA root certificate bundle
# dnf install -y ca-certificates
有効期限を無視する
相手のサーバのSSLの有効期限切れで証明書の更新なんてできない。
でもHTTPリクエストでスクレイピングしたい!ってときもあると思います。
SSLの証明書が切れているサイトの情報なんて信用性は薄いですが。
request-promiseにSSLの有効性を無視するオプション「strictSSL: false」を追加します。
import request from 'request-promise';
  let options = {
    method: 'GET',
    uri: url,
    strictSSL: false,  // SSLの有効性を無視
    headers: {
      'Content-Type': 'text/csv; charset=Shift_JIS',
    }
  };
let response = await request(options)
これでウェブスクレイピングできます。


