Unable to verify leaf signature
Asked Answered
W

19

211

I'm using node.js request.js to reach an api. I'm getting this error

[Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE]

All of my credentials are accurate and valid, and the server's fine. I made the same request with postman.

request({
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":{
        "X-API-VERSION": 1,
        "X-API-KEY": key
    },
}, function(err, response, body){
    console.log(err);
    console.log(response);
    console.log(body);
});

This code is just running in an executable script ex. node ./run_file.js, Is that why? Does it need to run on a server?

Wellgrounded answered 19/11, 2013 at 21:54 Comment(4)
This is a long shot, but could it be that the API is not recognizing the user agent being passed by your node program?Seicento
Hum...also see this: blog.gaeremynck.com/fixing-unable_to_verify_leaf_signatureSeicento
@HectorCorrea I was able to read the api in postman perfectly. Why can't node do it? I tried changing the user agent, no luck.Wellgrounded
Note that the issue here is caused by the same reason as this issue: stackoverflow.com/questions/31673587, and the (currently) top-scoring solution there, which refers to the certificate chain, is the best in-depth solution I've seenPivot
W
222

Note: the following is dangerous, and will allow API content to be intercepted and modified between the client and the server.

This also worked

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

Wellgrounded answered 20/11, 2013 at 15:51 Comment(7)
I upmodded this, and thanks for answering, but it's actively harmful to your security. You should add the missing CA per @CoolAJ86's answer below.Fagot
I am using the NodeJS plugin called nodemailer and nodemailer-smtp-transport and the same general command worked. You need to add this to your createTransport object: tls:{rejectUnauthorized: false}Matri
@Matri equally insecure with nodemailer I guess, though. There's a clue in the name: if something's Unauthorized, you generally want to reject it, by definition. What you need is to find a way to authorize it correctly (by setting up CA certificates properly, as other answers have already said).Trifocals
@Trifocals I agree, you should set it up the right way with certificates. I merely wanted to setup a quick test for a demo so the code I posted is a quick fix. I should have prefaced with that in my comment.Matri
@Fagot There is no security problem if the request is on the same server and you are the only owner.Davy
@BinarWeb Correct. I had this error happen, when multiple microservices on the same local developing enviroment "talked" to each other. The certificates were for the actual domains though so they were not valid locally.Nonrepresentational
It should be globally available in nodeCaesarea
L
104

It's not an issue with the application, but with the certificate which is signed by an intermediary CA. If you accept that fact and still want to proceed, add the following to request options:

rejectUnauthorized: false

Full request:

request({
    "rejectUnauthorized": false,
    "url": domain+"/api/orders/originator/"+id,
    "method": "GET",
    "headers":{
        "X-API-VERSION": 1,
        "X-API-KEY": key
    },
}, function(err, response, body){
    console.log(err);
    console.log(response);
    console.log(body);
});
Limburg answered 20/11, 2013 at 9:25 Comment(2)
I have this problem right now at work. I submitted an IT ticket telling them SSL may be misconfigured -- they told me I was craZY. Is there any more information I can give them to resolve this issue?Sheepfold
This isn't actually correct: as CoolAJ86 and hectorcorrea mention, the certificate is valid, but it's signed by an intermediary CA.Fagot
I
101

The Secure Solution

Rather than turning off security you can add the necessary certificates to the chain. First install ssl-root-cas package from npm:

npm install ssl-root-cas

This package contains many intermediary certificates that browsers trust but node doesn't.

var sslRootCAs = require('ssl-root-cas/latest')
sslRootCAs.inject()

Will add the missing certificates. See here for more info:

https://git.coolaj86.com/coolaj86/ssl-root-cas.js

Inclose answered 8/3, 2014 at 0:28 Comment(9)
Does the Http client not use the Windows Trusted Root Certification Authorities certificate store?Dermatosis
node uses the mozilla certs bundled in the binary and it overrides them whenever you supply your own ca array. I don't know if its http module will also look to the OS chain. However, curl on OS X seems to only use the OS chain and not allow manually specified certs.Inclose
Does this have to be run for each process or can I run it once and update my certificates globally?Carpology
The certificates are stored in potentially two places: (1) built-in to the node.js binary (2) the operating system keystore. If your certs are out of date you will need to include this in your running code. It doesn't change the node binary nor your operating system - just the project folder.Inclose
by the way github.com/coolaj86/node-ssl-root-cas is not anymore maintained, it sais "node-ssl-root-cas Moved to git.daplie.com/Daplie/node-ssl-root-cas" but in the issue Server down #34 github.com/Daplie/node-ssl-root-cas/issues/34 in the end sais "This is the real repo: git.coolaj86.com/coolaj86/ssl-root-cas.js".Angiosperm
Someone hijacked the redirects to my github projects by creating a spam account with my name. I've contacted github about it and hopefully it will be restored soon, then the links should work again.Inclose
I do get this error when trying this in Firebase Functions: Error: EROFS: read-only file system, open '/srv/node_modules/ssl-root-cas/pems/mozilla-certdata.txt' Any idea?Reprehensible
@Reprehensible It is exactly what the error messages says. I don't know how to explain it any simpler. It's a read-only file and cannot be edited.Inclose
I upvoted not for the answer itself, but for the article with "try this first" explanations behind the link provided by the author. Good job @Inclose ! Actually helpedFlowerer
A
60

CoolAJ86's solution is correct and it does not compromise your security like disabling all checks using rejectUnauthorized or NODE_TLS_REJECT_UNAUTHORIZED. Still, you may need to inject an additional CA's certificate explicitly.

I tried first the root CAs included by the ssl-root-cas module:

require('ssl-root-cas/latest')
  .inject();

I still ended up with the UNABLE_TO_VERIFY_LEAF_SIGNATURE error. Then I found out who issued the certificate for the web site I was connecting to by the COMODO SSL Analyzer, downloaded the certificate of that authority and tried to add only that one:

require('ssl-root-cas/latest')
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

I ended up with another error: CERT_UNTRUSTED. Finally, I injected the additional root CAs and included "my" (apparently intermediary) CA, which worked:

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');
Andros answered 31/8, 2014 at 10:52 Comment(4)
I was connecting to a web site with a certificated issued by the COMODO High-Assurance Secure Server CA. I downloaded the certificate from their downloads page.Andros
Thank you! For my issue I needed to add the entire chain of certs to get past this error. For others reference, this post showed me how to easily export the needed pem files via Firefox : superuser.com/a/97203Dropper
Well thanks for the help. In my case, in the end it was a bad configuration of the SSL server, not node. Not all the intermediate certs were installed on the server.Encrust
if you get the cert as a .cer run this openssl x509 -inform DER -in YOUR_CERTIFICATE.cer -out YOUR_CERTIFICATE.crt to convert it t a .crt beforehandGrath
R
23

For Create React App (where this error occurs too and this question is the #1 Google result), you are probably using HTTPS=true npm start and a proxy (in package.json) which goes to some HTTPS API which itself is self-signed, when in development.

If that's the case, consider changing proxy like this:

"proxy": {
  "/api": {
    "target": "https://localhost:5001",
    "secure": false
  }
}

secure decides whether the WebPack proxy checks the certificate chain or not and disabling that ensures the API self-signed certificate is not verified so that you get your data.

Ropy answered 21/9, 2018 at 20:52 Comment(0)
A
10

It may be very tempting to do rejectUnauthorized: false or process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; but don't do it! It exposes you to man in the middle attacks.

The other answers are correct in that the issue lies in the fact that your cert is "signed by an intermediary CA." There is an easy solution to this, one which does not require a third party library like ssl-root-cas or injecting any additional CAs into node.

Most https clients in node support options that allow you to specify a CA per request, which will resolve UNABLE_TO_VERIFY_LEAF_SIGNATURE. Here's a simple example using node's built-int https module.

import https from 'https';

const options = {
  host: '<your host>',
  defaultPort: 443,
  path: '<your path>',
  // assuming the bundle file is co-located with this file
  ca: readFileSync(__dirname + '/<your bundle file>.ca-bundle'),
  headers: {
    'content-type': 'application/json',
  }
};
https.get(options, res => {
  // do whatever you need to do
})

If, however, you can configure the ssl settings in your hosting server, the best solution would be to add the intermediate certificates to your hosting provider. That way the client requester doesn't need to specify a CA, since it's included in the server itself. I personally use namecheap + heroku. The trick for me was to create one .crt file with cat yourcertificate.crt bundle.ca-bundle > server.crt. I then opened up this file and added a newline after the first certificate. You can read more at

https://www.namecheap.com/support/knowledgebase/article.aspx/10050/33/installing-an-ssl-certificate-on-heroku-ssl

Ambur answered 4/9, 2019 at 20:41 Comment(2)
This bug comes mostly in local environment, not in production, So if you are in local its fine to do : process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';Fluky
@Vivex - it's not ok to do that in a local environment if the entire point is to test how your SSL certs work and how they get passed around...Crock
S
8

You can also try by setting strictSSL to false, like this:

{  
   url: "https://...",
   method: "POST",
   headers: {
        "Content-Type": "application/json"},
   strictSSL: false
}
Snaky answered 3/3, 2020 at 12:35 Comment(2)
This works if your sending from Node JS application, awesome!!Liquidity
Thank you!!! It works for me, wow, after spending so much time...Poolroom
R
7

I had the same issues. I have followed @ThomasReggi and @CoolAJ86 solution and worked well but I'm not satisfied with the solution.

Because "UNABLE_TO_VERIFY_LEAF_SIGNATURE" issue is happened due to certification configuration level.

I accept @thirdender solution but its partial solution.As per the nginx official website, they clearly mentioned certificate should be combination of The server certificate and chained certificates.

enter image description here

Ruddie answered 1/2, 2018 at 13:30 Comment(0)
O
3

Another approach to solving this securely is to use the following module.

node_extra_ca_certs_mozilla_bundle

This module can work without any code modification by generating a PEM file that includes all root and intermediate certificates trusted by Mozilla. You can use the following environment variable (Works with Nodejs v7.3+),

NODE_EXTRA_CA_CERTS

To generate the PEM file to use with the above environment variable. You can install the module using:

npm install --save node_extra_ca_certs_mozilla_bundle

and then launch your node script with an environment variable.

NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js

Other ways to use the generated PEM file are available at:

https://github.com/arvind-agarwal/node_extra_ca_certs_mozilla_bundle

NOTE: I am the author of the above module.

Outrank answered 25/12, 2019 at 5:32 Comment(0)
F
3

Following commands worked for me :

> npm config set strict-ssl false
> npm cache clean --force

The problem is that you are attempting to install a module from a repository with a bad or untrusted SSL[Secure Sockets Layer] certificate. Once you clean the cache, this problem will be resolved.You might need to turn it to true later on.

Foolscap answered 1/7, 2020 at 11:0 Comment(1)
Hey @shagun this doesn't work for me. if you have any other approach then please let me knowBohol
L
2

Just putting this here in case it helps someone, my case was different and a bit of an odd mix. I was getting this on a request that was accessed via superagent - the problem had nothing to do with certificates (which were setup properly) and all to do with the fact that I was then passing the superagent result through the async module's waterfall callback. To fix: Instead of passing the entire result, just pass result.body through the waterfall's callback.

Lakeishalakeland answered 18/12, 2015 at 15:2 Comment(0)
F
1

I had an issue with my Apache configuration after installing a GoDaddy certificate on a subdomain. I originally thought it might be an issue with Node not sending a Server Name Indicator (SNI), but that wasn't the case. Analyzing the subdomain's SSL certificate with https://www.ssllabs.com/ssltest/ returned the error Chain issues: Incomplete.

After adding the GoDaddy provided gd_bundle-g2-g1.crt file via the SSLCertificateChainFile Apache directive, Node was able to connect over HTTPS and the error went away.

Fanlight answered 17/11, 2017 at 18:25 Comment(0)
C
1

You have to include the Intermediate certificate in your server. This solves the [Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE]

Coati answered 22/5, 2019 at 8:12 Comment(0)
P
1

Hello just a small adition to this subject since in my case the

require('ssl-root-cas/latest')
  .inject()
  .addFile(__dirname + '/comodohigh-assurancesecureserverca.crt');

didn't work out for me it kept returning error that the file could not be downloaded i had been a couple of hours into the reasearch of this particular error when I ran into this response https://stackoverflow.com/a/65442604

Since in my application we do have a proxy to proxy some of our requests as a security requirement of some of our users I found that in the case you are consulting an API that has this issue and if you can access the API url throught your browser you can proxy your request and it might fix the [Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE] issue.

An example of how i use my proxy

await axios.get(url, {
  timeout: TIME_OUT,
  headers: {
    'User-Agent': 'My app'
  },
  params: params,
  proxy: {
    protocol: _proxy.protocol,
    host: _proxy.hostname,
    port: _proxy.port,
    auth: {
      username: _proxy_username,
      password: _proxy_password
    }
  }
});
Palpable answered 22/1, 2022 at 0:11 Comment(0)
A
1

I had the same problem and I am able to fix it the following way,

  1. Use the full-chain or just the chain certificate instead of just the certificate.

That is all.

Aer answered 3/10, 2022 at 7:2 Comment(0)
I
0

If you come to this thread because you're using the node postgres / pg module, there is a better solution than setting NODE_TLS_REJECT_UNAUTHORIZED or rejectUnauthorized, which will lead to insecure connections.

Instead, configure the "ssl" option to match the parameters for tls.connect:

{
  ca: fs.readFileSync('/path/to/server-ca.pem').toString(),
  cert: fs.readFileSync('/path/to/client-cert.pem').toString(),
  key: fs.readFileSync('/path/to/client-key.pem').toString(),
  servername: 'my-server-name' // e.g. my-project-id/my-sql-instance-id for Google SQL
}

I've written a module to help with parsing these options from environment variables like PGSSLROOTCERT, PGSSLCERT, and PGSSLKEY:

https://github.com/programmarchy/pg-ssl

Identify answered 12/5, 2020 at 14:22 Comment(0)
C
0

This same error can be received when trying to install a local git shared repo from npm. The error will read: npm ERR! code UNABLE_TO_VERIFY_LEAF_SIGNATURE Apparently there is an issue with the certificate, however what worked for me was change the link to my shared repo in the package.json file from: "shared-frontend": "https://myreposerver" to: "shared-frontend": "git+https://myreposerver"

In short, just adding git+ to the link solved it.

Cumshaw answered 18/10, 2022 at 7:53 Comment(0)
W
0

Another reason node could print that error is because a backend connection/service is misconfigured.

Unfortunately, the node error doesn't say which certificate it was unable to verify [feature request !]

Your server may have a perfectly good certificate chain installed for clients to connect and even show a nice padlock in the browser's URL bar, but when the server tries to connect to a backend database using a different misconfigured certificate, then it could raise an identical error.

I had this issue in some vendor code for some time. Changing a backend database connection from self-signed to an actual certificate resolved it.

Whity answered 2/11, 2022 at 6:2 Comment(0)
D
0

I've just stumbled upon this issue hoping to find a solution that doesn't require to ignore validation or make changes to the application as this issue is not caused by it.

The solution that worked in my case was to update the OS certificate bundle.

These commands can be used as root to upgrade the certificate package in common Linux distros:

  • Alpine without ca-certificates (Docker images will do this to keep smaller sizes):
    apk add --upgrade --no-cache ca-certificates-bundle
  • Install or update ca-certificates in distros with APT:
    apt install -y ca-certificates
  • Install or update ca-certificates in distros with YUM:
    yum install -y ca-certificates
Dishwater answered 1/4 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.