Nodejs https request UNABLE_TO_GET_ISSUER_CERT_LOCALLY

29,509

Solution 1

There is a reason for SSL. Besides other features, it authenticates that you are really communicating with the server identified by private.service.com hostname. Otherwise your client software can be cheated by a Man-in-the-Middle attack.

First when anyone encounters this issue, they should update system root SSL certificates. In Debian they are contained in ca-certificates apt-get package.

If it doesn't help, the server probably uses an issuer certificate, which is not trusted by default worldwide PKI infrastructure. In this case the client should compare the certificate public key signature with a preshared value. This is known as "certificate pinning".

Specifically to your error, if it worked before, it is possible that the server certificate has expired. The server should renew it. As a temporary solution, you can turn off PKI validation by rejectUnauthorized option. However you should use it together with the pinning approach. In NodeJS, you can get the server certificate fingerprint from res.socket.getPeerCertificate().fingerprint.

Solution 2

After some study i found that this is a problem of the server that i'm trying to make the https request to.

Node https cannot find the ssl ISSUER_CERT on the private.service server and so it throw that exception.

The solution i used, since i'm sure i can trust that server, was to add

            rejectUnauthorized: false

to the options of the https request, this way node will not throw an exception in case of certificates problem.

Anyway this solution is valid only if you know you can trust the host of your request, otherwise it's probably not the best solution.

Solution 3

After a reasearch this solved the problem:

npm set strict-ssl=false

Hope it helps.

Solution 4

From this GitHub issue, use the following environment variable:

export NODE_EXTRA_CA_CERTS=/path/to/certfile.crt

After this, you can run any of the npm commands and nodejs will trust your extra certificate file.

The .crt file is a file that contains a prefix line, the base64 encoded cert and a suffix line.

If you don't have your root CA cert handy, you can generate the cert file from your URL, with the openssl command:

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

Where <host> is the hostname of the url. For example, using google.com for the host, the output looks something like this:

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

Save that as your .crt file and add its path to the NODE_EXTRA_CA_CERTS environment variable and you're all set.

Share:
29,509
pietrovismara
Author by

pietrovismara

Updated on July 30, 2020

Comments

  • pietrovismara
    pietrovismara over 3 years

    OS: debian sid

    Nodejs: v0.10.38

    I have a request to a private service that use authentication:

    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);
    });

    When i run the script, node throws this error:

    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)
    

    The same exact script worked well for months, and i'm sure the authentication is correct. Today is the first time i have this situation.

    Which can be the cause for this error?