2

I have 2 Node.js applications accessible via HTTPS. I'm currently using self-signed certificates for those services. Manual access (via a browser or Postman) to those services work as expected (with the usual security warnings about self-signed certificates, etc.).

But as for now, I cannot have one application communicate with the other via HTTPS. Here's my current code:

// Request parameters and options
const https = require('https');
const postData = JSON.stringify(myPostData);
const options = {
  hostname: '...',
  port: ...,
  path: '...',
  method: 'POST',
  headers: {
      'Content-Type': 'application/json',
      'Content-Length': postData.length,
  },
  rejectUnauthorized: false,
};
let str = '';
const req = https.request(options, (res) => {
  // Assembling response data...
  res.on('data', chunk => str += chunk );
  res.on('end', () => {
    console.log('Received:', str);
  });
});
// Error handling
req.on('error', (e) => {
  console.error(e);
});
// Sending payload and terminating
req.write(postData);
req.end();

Question

This works, but only because I use rejectUnauthorized: false.

How can I avoid to use this option? I see that I can provide a cert option (in https.RequestOptions), but I'm unsure of how to use it. As I created the self-signed certificate, I possess every pieces of it.

My cert file, named selfsigned.crt, looks like this (and has Unix EOL):

-----BEGIN CERTIFICATE-----
MFoXDTI0MTEyNTE3NTczMFowgYcxCzAJBgNVBAYTAkZSMQ0wCwYDVQQIDARQQUNB
QGNlbmVhdS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCrP3Hy
........... lots of lines ......................................
zI2hWprwsM3PGb0DLCqlotqdoxu59PQRC7aj/yb11HyfyYO9hvFmjGPkmN6T0+r6
VQQGEwJGUjENMAs/Qs7p+B9/+taee8iPWpk=
-----END CERTIFICATE-----

I have tried these solutions:

  • indicated the cert string as the ca and/or cert request options (see their description) - I know this is actually taken into account, as if the string is malformed, the error is different (and related to the certificate format)
  • indicated the path of the cert to the 'NODE_EXTRA_CA_CERTS' environment variable, as suggested by Ashish Modi)
  • copied the cert file in the /etc/ssl/certs/ (calling application OS is debian) and launched update-ca-certificates

All of those solutions change nothing to the outcome:

code: DEPTH_ZERO_SELF_SIGNED_CERT
Error: self signed certificate
      at TLSSocket.onConnectSecure (_tls_wrap.js:1055:34)

As for now, I still don't have a working solution.

Bonus question! I'm very surprised how messy a simple call can look, all chronologically upside-down it gets with the callbacks. Is there a cleaner way to proceed a HTTPS call? => request-promise might be an option, as indicated by jfriend00

Bob
  • 1,495
  • 1
  • 19
  • 24
  • 1
    *Is there a cleaner way to proceed a HTTPS call?* - Yeah, use the `request-promise` library with promises. You can also even use `async/await` with the promise if you want. `https.request()` with plain callbacks is like going down to bare metal when you have much higher level and easier to use options built on top of that. – jfriend00 Nov 26 '19 at 18:46
  • That was fast! = ) This library sounds indeed promising, thanks! I'll go to it. I'll have to set-up my certificate with this one too though, but it seems one can use the same agent options, so as soon as I'll know how... – Bob Nov 26 '19 at 19:00
  • 1
    Yeah, on the cert stuff, I don't know exactly how to do it myself, but conceptually, you want to teach the local client to trust your self-signed CA. I am curious how one does that so I'm tracking the question hoping someone else can show you the way. – jfriend00 Nov 26 '19 at 19:02
  • 1
    I'm very surprised how I'm struggling finding documentation about how to deal with self-signed certs. When using it internally (between internal services), I'd have thought it would not be unusual to do so. – Bob Nov 26 '19 at 19:06
  • Maybe see the code [in this article](https://community.apigee.com/articles/28041/nodejs-and-self-signed-ssl-certificates.html) under the heading: "Define https Request Program". There you specify a CA as part of the request. – jfriend00 Nov 26 '19 at 19:12
  • Also, read this: [tls.createSecureContext()](https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options). The TLS library in node.js is what `https.request()` and `request()` and `request-promise()` is built on top of. The operative part of that function is the `ca` option which starts with this description: ***Optionally override the trusted CA certificates***. – jfriend00 Nov 26 '19 at 19:33
  • Thank you for the resources. By specifying the ca/cert options, I have some progress now: "error:0909006C:PEM routines:get_name:no start line". Or is it backward progress? ; ) Actually yes, that happens when I omit the beginning "-----BEGIN CERTIFICATE-----" line. So at least, something is taken into account here! ; ) I'll have to see to that tomorrow. Thx again! – Bob Nov 26 '19 at 20:14
  • I am facing the same issue and not able to find any working solution on the web. Could you solve this issue? Do you have a working solution somewhere on github? – Namrata Kumari May 09 '22 at 07:00
  • Unfortunately no. I've migrated to a system using non-self-signed certificates (by using Let's Encrypt free ones). – Bob May 09 '22 at 11:10

1 Answers1

0

This option can be set to pass the extra certs

process.env["NODE_EXTRA_CA_CERTS"] = "some/path/to/ssl.crt"

This option can completely disable the ssl errors (not recommended)

process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;

Hope this helps.

Ashish Modi
  • 7,529
  • 2
  • 20
  • 35
  • 1
    Thanks for the suggestion! Unfortunately, it didn't work in my case. I've edited my question to reflect my current state of investigation. – Bob Nov 27 '19 at 16:54