Host: localhost. is not in the cert's altnames - node.js

I'm getting the below error while doing server-side rendering.
RENDERING ERROR: { [Error: Network error: request to https://api-dev.xyz.io/graphql failed, reason: Hostname/IP doesn't match certificate's altnames: "Host: localhost. is not in the cert's altnames: DNS:*.xyz.io"]
graphQLErrors: null,
networkError:
{ [FetchError: request to https://api-dev.xyz.io/graphql failed, reason: Hostname/IP doesn't match certificate's altnames: "Host: localhost. is not in the cert's altnames: DNS:*.xyz.io"]
name: 'FetchError',
message: 'request to https://api-dev.xyz.io/graphql failed, reason: Hostname/IP doesn\'t match certificate\'s altnames: "Host: localhost. is not in the cert\'s altnames: DNS:*.xyz.io"',
type: 'system',
errno: undefined,
code: undefined },
message: 'Network error: request to https://api-dev.xyz.io/graphql failed, reason: Hostname/IP doesn\'t match certificate\'s altnames: "Host: localhost. is not in the cert\'s altnames: DNS:*.xyz.io"',
extraInfo: undefined }
Note:- I'm using react, redux, apollo-client(GraphQL) and ExpressJS(NodeJS). The API server to which I'm making the request is on another domain and I can't make any change on that.
While working with client-side rendering I'm not facing any difficulties everything is working as intended but while doing server-side render I'm getting the above error.
So I tried the below approaches on my server but still no luck.
Adding self-signed certificate
Adding 'rejectUnauthorized':false in https options.
const options = {
'key': key,
'cert': cert,
'ca': [ fs.readFileSync('local-certificate.pem') ],
'rejectUnauthorized':false
};
https.createServer(options, app).listen(httpsPort, '0.0.0.0', function onStart(err) {
if (err) { console.log(err); }
console.info('==> Listening on httpsPort %s. Open up http://0.0.0.0:%s/ in your browser.', httpsPort, options);
});
Also I tried to add an alt name in my self-signed certificate with the help of How can I generate a self-signed certificate with SubjectAltName using OpenSSL?
Is there any way to bypass certificate verification so that my express server can make a request to the API server which is on another domain with a valid certificate?
I'm still a bit unsure whether I can fix it by making any changes at my end (on my express server).
Please let me know any insights on this.

The error is not caused by the code you have in your question.
What you are doing is that you are creating a new HTTP server, that will listen to httpsPort and will bind to 0.0.0.0 which means all local IP addresses.
I suggest you omit 0.0.0.0 when binding to all local IP addresses since this is the default behavior anyway, but this is not a problem.
Then you are assigning this server the certificate local-certificate.pem which means that clients connecting to this server will be presented this certificate.
You are not connecting to any external APIs in this part of the code.

I believe Michael Landis was trying to get this point across, but didn't quite provide the solution. If your service is running on locally on 192.168.100.100, then this needs to be in your hosts file (e.g. /etc/hosts on linux):
192.168.100.100 api-dev.xyz.io
The request that's currently failing needs to be made to api-dev.xyz.io, even during SSR. It's much easier to avoid the requests to "http[s]://localhost/...".

The error message is stating that the server at https://api-dev.xyz.io/graphql believes that the incoming request is being directed to https://localhost/graphql. Therefore, it is failing because the SSL certificate is not securing https://localhost/.
Could your server-side rendering be trying to perform a fetch/API call to the same server that is doing the server-side rendering to load initial data for the render? If so, could the initial data that the client needs from the API be passed to the server-side rendering directly instead of React trying to perform an API call to itself in the server-side render?
Perhaps this tutorial could be used as an example reference.

The host name is a system-level setting below NodeJS. You'll need to have access to the the box/VM your copy of NodeJS is running on.

Related

Watson Assistant - UNABLE_TO_GET_ISSUER_CERT_LOCALLY

I am trying to connect my NodeJS client application running locally from within a corporate proxy to Watson Assistant Service.
To set-up connection, I am using the following code.
var HttpsProxyAgent = require('https-proxy-agent');
var httpsAgent = new HttpsProxyAgent("<proxyserver:port>");
var assistant = new AssistantV2({
version: '2019-02-28',
authenticator: new IamAuthenticator
({apikey: *<apikey here>*, httpsAgent}),
url: 'https://gateway-wdc.watsonplatform.net/assistant/api',
disableSslVerification: true,
httpsAgent,
});
But, I get the following error in console
Server running on port: 3100
{ Error: unable to get local issuer certificate
at RequestWrapper.formatError (*<actual path hidden>*\node_modules\ibm-watson\node_modules\ibm-cloud-sdk-core\lib\request-wrapper.js:208:21)
at *<actual path hidden>*\node_modules\ibm-watson\node_modules\ibm-cloud-sdk-core\lib\request-wrapper.js:196:25
at processTicksAndRejections (internal/process/next_tick.js:81:5)
message: 'unable to get local issuer certificate',
statusText: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
body:
'Response not received - no connection was made to the service.' }
Kindly advise.
This problem is caused by your proxy performing TLS intercept.
You have several options:
set strict-ssl=false.
set NODE_EXTRA_CA_CERTS=fullpath_to_certificates_file
For the first method, you are disabling certificate validation. This might be OK in a controlled environment (your source code) but make sure you know what you are doing.
For the second method, ask your admin for the SSL root and intermediate certificates. Basically, you are telling your system to trust those certificates.

LetsEncrypt working for IP but not Domain (greenlock, express)

I am using the following server script to run both http, https servers and redirect all http requests to https.
When I access the server both locally and remotely from IP addresses, the requests redirect to https and api works with an unsecure warning.
But when I access the same routes via domain, I get "Site cannot be Reached" error.
Although, accessing http://example.com/test-route redirects to https://example.com/test-route, I am still getting Site can't be reached error.
import http from 'http';
import https from 'https';
import redirectHttps from 'redirect-https';
import greenlock from 'greenlock';
import app from '../app';
var le = greenlock.create({
server: 'staging', // using https://acme-v01.api.letsencrypt.org/directory in prod
configDir: 'certs',
approveDomains: (opts, certs, cb) => {
if (certs) {
opts.domains = ['example.com']
} else {
opts.email = 'me#mymail.com',
opts.agreeTos = true;
}
cb(null, {
options: opts,
certs: certs
});
},
});
http.createServer(le.middleware(redirectHttps())).listen(80, function() {
console.log("Server Running On http # port " + 80);
});
https.createServer(le.httpsOptions, le.middleware(app)).listen(443, function() {
console.log("Server Running On https # port " + 443);
});
There's a number of reasons that this could be happening, and a lot has been updated in the library since you posted this question.
I've spent a lot of time recently updating the documentation and examples:
https://git.coolaj86.com/coolaj86/greenlock-express.js
I'd suggest taking a look at the video tutorial:
https://youtu.be/e8vaR4CEZ5s
And check each of the items in the troubleshooting section. For reference:
What if the example didn't work?
Double check the following:
Public Facing IP for http-01 challenges
Are you running this as a public-facing webserver (good)? or localhost (bad)?
Does ifconfig show a public address (good)? or a private one - 10.x, 192.168.x, etc (bad)?
If you're on a non-public server, are you using the dns-01 challenge?
correct ACME version
Let's Encrypt v2 (ACME v2) must use version: 'draft-11'
Let's Encrypt v1 must use version: 'v01'
valid email
You MUST set email to a valid address
MX records must validate (dig MX example.com for 'john#example.com')
valid DNS records
You MUST set approveDomains to real domains
Must have public DNS records (test with dig +trace A example.com; dig +trace www.example.com for [ 'example.com', 'www.example.com' ])
write access
You MUST set configDir to a writeable location (test with touch ~/acme/etc/tmp.tmp)
port binding privileges
You MUST be able to bind to ports 80 and 443
You can do this via sudo or setcap
API limits
You MUST NOT exceed the API usage limits per domain, certificate, IP address, etc
Red Lock, Untrusted
You MUST change the server value in production
Shorten the 'acme-staging-v02' part of the server URL to 'acme-v02'
Please post an issue at the repository if you're still having trouble and I'll do my best to help you sort things out. Make sure to upgrade to the latest version because it has better debug logging.

nodejs with ssl (https to https) Error: unable to verify the first certificate

i have two projects in the same server, 1st:
php with nginx in port 443, thats an api rest.
2nd: nodejs in port 80 this is a consuming of rest api.
1st and 2nd works alone fine and both have a ssl certificate but when i try to access api from node js to api returns exception
Error: unable to verify the first certificate
if both applications use "http" works fine, and node can access to api rest. to consume api rest in node i use "node-rest-client" i try use this args but doesn't work:
connection:{
secureOptions: constants.SSL_OP_NO_TLSv1_2,
ciphers: 'ECDHE-RSA-AES256-SHA:AES256-SHA:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM',
honorCipherOrder: true
}
Does anyone know why this happens?

Using Node.js with TLS getting HTTP hostname wrong error

I'm trying to write a simple Node.js server applicationthat will accept client requests, and allowing me to change the TLS/SSL protocol to use. It works fine with a browser (Firefox).
However, when I call the Node.js server from WebSphere Liberty Profile, no matter which TLS/SSL protocol I try to use, I am getting the very confusing error message:
[ERROR ] IOException invoking https://dlwester:32080/W3CookieServiceEmulator/workplace/services/w3cookie/callback/auth_data: HTTPS hostname wrong: should be <dlwester>
As you can see, it's telling me I'm using the wrong hostname, but the hostname it's telling me I should be using is what I'm already using. I've even tried using port 443, so that I don't need to specify a port, but it still gives me the same error message.
I'm not sure if the error is with Node.js or my WLP code (using JAX-RS client). I've not found a way in Node.js to bypass verifying the hostname.
var options = {
key: 'my.key',
cert: 'my.cert',
ciphers: 'TLSv1.2,TLSv1.1,TLSv1.0,SSLv3',
honorCipherOrder: true,
rejectUnauthorized: false
}
server = https.createServer(options, requestListener);
So I guess that's my first question - can I bypass hostname verification?
Has anyone else run into this error, and know a way to get around it?
This is the client verifying the hostname, not the server. You never mentioned the hostname used in your certificate -- if it doesn't match the hostname you use to address it from the client: fix the certificate.

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:
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.
set this process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
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:
ssl-tools.net site provides root & intermediate certificates. For example: Baltimore CyberTrust Root used by lives.api.net
ssl-root-cas module claims to provide additional CA certificates as used by popular browsers. I have not verified the claim.
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.
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.
Set this process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
Fixed the UNABLE_TO_VERIFY_LEAF_SIGNATURE problem for superagent.
Try this in command line:
npm config set strict-ssl false
It worked for me on mac.

Resources