Node.js https 请求 UNABLE_TO_GET_ISSUER_CERT_LOCALLY

Nodejs https request UNABLE_TO_GET_ISSUER_CERT_LOCALLY

OS:debian sid

节点:v0.10.38

我有一个使用身份验证的私人服务请求:

var https = require('https');

var options = {
    host: 'private.service.com',
    path: '/accounts/' + '123323' + '/orders',
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': 0,
        'Authorization': 'Bearer ' + 'asdsdgcvxcvxcv'
    }
};

var request = https.request(options, function (res) {
    console.log(res);
});

当我 运行 脚本时,节点抛出此错误:

events.js:72
    throw er; // Unhandled 'error' event
          ^
Error: UNABLE_TO_GET_ISSUER_CERT_LOCALLY
    at SecurePair.<anonymous> (tls.js:1381:32)
    at SecurePair.emit (events.js:92:17)
    at SecurePair.maybeInitFinished (tls.js:980:10)
    at CleartextStream.read [as _read] (tls.js:472:13)
    at CleartextStream.Readable.read (_stream_readable.js:341:10)
    at EncryptedStream.write [as _write] (tls.js:369:25)
    at doWrite (_stream_writable.js:226:10)
    at writeOrBuffer (_stream_writable.js:216:5)
    at EncryptedStream.Writable.write (_stream_writable.js:183:11)
    at write (_stream_readable.js:602:24)

同一个脚本几个月来运行良好,我确信身份验证是正确的。今天是第一次遇到这种情况。

导致此错误的原因是什么?

经过一番研究,我发现这是我尝试向其发出 https 请求的服务器的问题。

节点 https 在 private.service 服务器上找不到 ssl ISSUER_CERT,因此抛出该异常。

我使用的解决方案是添加

,因为我确定我可以信任该服务器
            rejectUnauthorized: false

https请求的选项,这样节点在证书问题的情况下不会抛出异常。

无论如何,只有当您知道可以信任您的请求的主机时,此解决方案才有效,否则它可能不是最佳解决方案。

SSL 是有原因的。除了其他功能外,它还可以验证您是否真的在与 private.service.com 主机名标识的服务器通信。否则您的客户端软件可能会被中间人攻击欺骗。

首先,当任何人遇到此问题时,他们应该更新系统根 SSL 证书。在 Debian 中,它们包含在 ca-certificates apt-get 包中。

如果没有帮助,服务器可能使用了颁发者证书,默认情况下全球 PKI 基础设施不信任该证书。在这种情况下,客户端应将证书 public 密钥签名与预共享值进行比较。这被称为 "certificate pinning"。

具体针对您的错误,如果之前有效,则可能是服务器证书已过期。服务器应该更新它。作为临时解决方案,您可以通过 rejectUnauthorized 选项关闭 PKI 验证。但是,您应该将它与固定方法一起使用。在 NodeJS 中,您可以从 res.socket.getPeerCertificate().fingerprint.

获取服务器证书指纹

当我尝试在 Ubuntu 16 上安装 npm 时,我遇到了同样的错误。 以下命令对我有用。

npm config set registry http://registry.npmjs.org/

经过研究,问题解决了:

npm set strict-ssl=false

希望对您有所帮助。

来自 this GitHub issue,使用以下环境变量:

export NODE_EXTRA_CA_CERTS=/path/to/certfile.crt

在此之后,您可以 运行 任何 npm 命令,nodejs 将信任您的额外证书文件。

.crt 文件是一个包含前缀行、base64 编码证书和后缀行的文件。

如果您手边没有根 CA 证书,您可以使用 openssl 命令从 URL 生成证书文件:

openssl s_client \
    -showcerts \
    -servername <host> \
    -connect <host>:443 2>/dev/null </dev/null | \
  openssl x509

其中 <host> 是 url 的主机名。例如,使用 google.com 作为主机,输出如下所示:

-----BEGIN CERTIFICATE-----
MIIIIDCCBwigAwIBAgIQI/1aCHwDN94QFUhXJeIwODANBgkqhkiG9w0BAQsFADBU
(42 more lines)
E+Hv1bJSbOMSNCDzqRM3JUzvM6Y=
-----END CERTIFICATE-----

将其保存为您的 .crt 文件并将其路径添加到 NODE_EXTRA_CA_CERTS 环境变量中,一切就绪。