10

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:

  • The request must be made on HTTPS protocol (not HTTP)
  • The request must be made using a LAN IP address, because the domain name will not work internally
  • The request must appear to be requesting from the external domain name, because that is what the Virtual Host is setup for.

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.

Morten Siebuhr
  • 5,812
  • 4
  • 27
  • 41
jwegner
  • 6,063
  • 8
  • 32
  • 55
  • do you have a line like this somewhere above that `var https = require('https');` ? – Mike L. Feb 25 '12 at 01:06
  • @MikeL. Yup. https is a global variable, and I know it's working because the actual HTTPS request fires - it's just responded to with a 400 error. – jwegner Feb 25 '12 at 01:08
  • your also missing `method:['get','post']` in your options...heres the docs http://nodejs.org/docs/v0.4.0/api/https.html#https.request – Mike L. Feb 25 '12 at 01:09
  • @MikeL. just added - no luck. – jwegner Feb 25 '12 at 01:10
  • 1
    Im looking into the `authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'` error now...is your SSL cert. self-signed? – Mike L. Feb 25 '12 at 01:12
  • @MikeL. Nope - the cert is "verified by GoDaddy", according to Chrome. – jwegner Feb 25 '12 at 01:13
  • Is the server expecting the client to present a certificate? What information can you find in the server's error logs? – sarnold Feb 25 '12 at 01:16
  • @sarnold Unfortunately, I don't have access to the logs yet. I'm currently working on getting to them, but my boss(es) aren't responding. – jwegner Feb 25 '12 at 01:26
  • possible duplicate of [Unable to verify leaf signature](http://stackoverflow.com/questions/20082893/unable-to-verify-leaf-signature) – user456584 Apr 09 '15 at 00:29

5 Answers5

16

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

ThomasReggi
  • 42,912
  • 63
  • 199
  • 343
  • 1
    thanks! this fixed my issue with node.js and zombie and being able to watch the HTTPs traffic in fiddler ( as well as having to set the zombie browser option to the fiddler proxy ) – Ron Dec 07 '13 at 15:10
  • 3
    This is a lousy idea. If the system has the proper CA root (AKA anchor) certificates, there should be a way to tell Node about them instead of turning off `strict-ssl`. – docwhat May 12 '14 at 20:30
1

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.
Sushil
  • 4,356
  • 2
  • 15
  • 15
0

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.

Mike L.
  • 1,886
  • 6
  • 21
  • 36
  • http://devel.dyne.org/jmx/tree/jsapi/node/tls.js?id=c3cf7e8d0000baf0af7e2c236fb5dd6ccde14439 here is the source, look around line 755 – Mike L. Feb 25 '12 at 01:17
  • 2
    I think you may have my situation a little backwards. This (I believe) is if I'm creating an SSL server - the verbage in that document seems to suggest that requestCert and rejectUnauthorized are set on the server. I, however, am trying to make a HTTPS request from a different (apache) server. – jwegner Feb 25 '12 at 01:25
  • If that is the case, then `UNABLE_TO_VERIFY_LEAF_SIGNATURE` is something that your server is returning to you, that error has nothing to do with node.js – Mike L. Feb 25 '12 at 01:33
  • 1
    @MikeL. This is bull. I right now have a simple request function to an external API and I'm getting `UNABLE_TO_VERIFY_LEAF_SIGNATURE` and in Postman the same headers are being applied and it is working perfectly. Why is that? How can you tell me it has nothing to do with node? – ThomasReggi Nov 19 '13 at 22:32
-1

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

Jatin
  • 2,967
  • 6
  • 26
  • 42
kenny
  • 1
-3

Try this in command line:

npm config set strict-ssl false

It worked for me on mac.

gotqn
  • 36,464
  • 39
  • 145
  • 218
  • This is a lousy idea. If the system has the proper CA root (AKA anchor) certificates, there should be a way to tell Node about them instead of turning off `strict-ssl`. – docwhat May 12 '14 at 20:29