jwegner
jwegner

Reputation: 7403

Node.js HTTPS 400 Error - 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'

I'm writing a Node.js app that has to request some data from one of our internal APIs. The tricky part is that the server I'm requesting data from has certain limitations:

In order to do this, I'm running a bit of code that looks like this:

var headers = {
    Host: externalHostname,
    Hostname: externalHostname,
};

var options = {
    host: InternalIP,
    path: path,
    method: 'GET',
    headers: headers
};

var req = https.request(options, function(res) {
    res.setEncoding('utf8');

    var data = "";

    res.on('data', function(chunk) {
        data += chunk;
    });

    res.on('end', function() {
        //Do something with that data
    });

    res.on('error', function(err) {
            console.log("Error during HTTP request");
            console.log(err);
    });
});

req.end();

Unfortunately, I'm getting a 400 (Your browser sent a request that this server could not understand) error as a response. I've double and triple checked that the hostname, ip address, and path name are all correct (I can test them from within my browser, and all is good).

I did an output of my response variable (res), and am receiving an authorizationError value of UNABLE_TO_VERIFY_LEAF_SIGNATURE. I'm not sure what that is, or if it's my problem, but it's the only useful bit of information I could find.

I put a full output of my response variable here.

Any ideas on what might be causing this?

Update: I figured it out! I was trying to authenticate with the server by passing a ?PHPSESSID=asdad GET variable, but they have that disabled. I was able to make it work by setting PHPSESSID in the Cookie header.

Upvotes: 11

Views: 16613

Answers (5)

Sushil
Sushil

Reputation: 5535

I hit here while debugging UNABLE_TO_VERIFY_LEAF_SIGNATURE error in an external api call from my nodejs server.

This error is hit when there is error during verification of the server certificate. While it is not recommended to disable the security by the following code (which is also available as another answer), it helps to verify if you are chasing the right bug. In other words, if putting this also does not fix it, there is something else wrong with the code.

process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

In my case, there was silly bug & request was going to localhost itself. Even after putting the above, request failed and that helped me uncover the bug.

Having said that, it is not recommended to use this as a solution. Rather figure out how you can provide additional certificates by setting agent:false & ca:[fs.readFileSync('root-cert.pem')] options. https.request documentation provides details. While chasing my bug, I also found few more useful resources:

  1. ssl-tools.net site provides root & intermediate certificates. For example: Baltimore CyberTrust Root used by lives.api.net
  2. ssl-root-cas module claims to provide additional CA certificates as used by popular browsers. I have not verified the claim.
  3. openssl s_client -connect apis.live.net:443 -- prints the certificate chain. you need to replace the last parameter (url & port) with what you are connecting to.

Upvotes: 1

user3521065
user3521065

Reputation: 1

Try this in command line:

npm config set strict-ssl false

It worked for me on mac.

Upvotes: -3

kenny
kenny

Reputation: 1

Set this process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; Fixed the UNABLE_TO_VERIFY_LEAF_SIGNATURE problem for superagent.

Upvotes: -1

ThomasReggi
ThomasReggi

Reputation: 59345

set this process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';

Upvotes: 16

Mike L.
Mike L.

Reputation: 1966

check this out from the tls.js source in the latest node.js (there is much more this is what I think you need)

// AUTHENTICATION MODES
//
// There are several levels of authentication that TLS/SSL supports.
// Read more about this in "man SSL_set_verify".
//
// 1. The server sends a certificate to the client but does not request a
// cert from the client. This is common for most HTTPS servers. The browser
// can verify the identity of the server, but the server does not know who
// the client is. Authenticating the client is usually done over HTTP using
// login boxes and cookies and stuff.
//
// 2. The server sends a cert to the client and requests that the client
// also send it a cert. The client knows who the server is and the server is
// requesting the client also identify themselves. There are several
// outcomes:
//
//   A) verifyError returns null meaning the client's certificate is signed
//   by one of the server's CAs. The server know's the client idenity now
//   and the client is authorized.
//
//   B) For some reason the client's certificate is not acceptable -
//   verifyError returns a string indicating the problem. The server can
//   either (i) reject the client or (ii) allow the client to connect as an
//   unauthorized connection.
//
// The mode is controlled by two boolean variables.
//
// requestCert
//   If true the server requests a certificate from client connections. For
//   the common HTTPS case, users will want this to be false, which is what
//   it defaults to.
//
// rejectUnauthorized
//   If true clients whose certificates are invalid for any reason will not
//   be allowed to make connections. If false, they will simply be marked as
//   unauthorized but secure communication will continue. By default this is
//   false.
//

set rejectUnauthorized to false in your options and cross your fingers...let me know if the output changes.

Upvotes: 0

Related Questions