Node.js generate LetsEncrypt.org SSL certificate with specific common name - node.js

I am currently trying to create a LetsEncrypt SSL certificate package using the node letsencrypt package (https://www.npmjs.com/package/letsencrypt). I have managed to generate a standard certificate suite using the following code.
'use strict';
var express = require('express');
var LE = require('letsencrypt');
var le;
// server = staging for test encryption cert generation
// server = production for generating verified certificate
var le = LE.create({ server: 'production' });
// Define encryption certificate options as JSON object
var opts = {
domains: ['www.mydomain.com'], email: 'me#mydomain.com', agreeTos: true
};
// Submit certificate signing request to LetsEncrypt.
// Print certificates, keys (i.e. pem files) when received from server.
le.register(opts).then(function (certs) {
console.log(certs);
// privkey, cert, chain, expiresAt, issuedAt, subject, altnames
}, function (err) {
console.error(err);
});
var app = express();
// Create server listening on port 80 to handle ACME challenges
// i.e. basic web server to serve files so CA can verify website ownership
app.listen(80, function () {
console.log('Basic server started and listening on port 80');
console.log('Server handling basic ACME protocol challenges');
});
// Allow access to all static files in server directory
// Enables CA to access file served up to verify domain ownership
app.use('/', le.middleware());
Which works fine and generates me a trusted certificate from LetsEncrypt.org when accessed via www.mydomain.com. However, when I try to access my website on my internal (local) network via 192.168.0.myserveraddress. I get the following error:
Does anyone know how I can modify the common name in the certificate request to LetsEncrypt to 192.168.0.myserveraddress so I don't get this error when accessing my website via our local area network?

I actually solved this issue by setting up our local area network to allow loopback connections using what is called NAT Loopback.
This means I do not need to use the local IP address (192.168.0.myserveraddress) to access my server anymore and can just use www.mydomain.com to access it internally.
Since this maintains the domain name the certificate is now trusted and I no longer have the above error.
Additionally I believe that certificate authorities (i.e. LetsEncrypt) will not issue certificates for IP addresses. So the only way you can resolve the above error is to access the website via its domain name. See link below.
https://community.letsencrypt.org/t/certificate-for-static-ip/84.

Related

What key should I use to sign an intermediate SSL certificate for a reversed proxied HTTPS connection?

I have an Apache server hosting a couple webpages, and an express server running on another machine that connects via a reverse proxy to the apache server, providing an endpoint to the webpage. The webpage is already running on HTTPS with valid certificates, but now I have to configure the express server to do the same with the intermediate certificates, I believe Which private key should I use to setup this service? Or are the intermediate certs signed by the apache head? I don't think that is the case since the configuration dones't work without a key, but I still cannot get my head around how this works if the certificates are issued at the same time the private key of the server is generated. How is it possible to cofigure intermediate connections with intermediate certs if the intermediate servers didn't exist when the certificates where issued?
This is the express server configuration so far:
const options = {
// The same certificate apache uses. Is this right?
cert: fs.readFileSync(config.ssl.dir + config.ssl.cert)
// The three sections of the bundle the issuer provided
ca: [],
// The private key I don't have (its in the other server)
key: fs.readFileSync(config.ssl.dir + config.ssl.key),
};
config.ssl.ca.forEach((value) => {
if (value) options.ca.push(fs.readFileSync(config.ssl.dir + value));
});
server = https.createServer(options, app);
Some more information, I have three files:
certificate.csr, the one the apache server uses and works, so I think it is the root certificate
certificate.pem, with the exact same contents as certificate.csr
a_bundle.csr, with three sections. I believe those are the intermediate certs.
These files were provided by GoDaddy.com when buying the ssl certificates, but with meaningless names.

validate https requests using a Certificate Authority (CA)

I have deployed multiple microservices containing frontend application and backend service.
The frontend application is accessible via xyz.com domain. It calls the backend service API endpoint.
So, what I really want is to check is that if any request that is coming from the frontend application is valid and from authentic source on the basis of its domain and subdomain using Certificate Authority in Node.js.
After doing a little bit of research about how it can be done in node.js,
I found out that it can be done using nodejs https module's request method. But the problem with this approach is that nodejs maintains a list of CA certs, which easily gets out of date and there is a chance that the CA that has verified my domain certificate is not part of that list. Although they provide a way to pass additional CA's but still it is a dependency on the user side that they have to maintain the list. I am currently a little bit lost on how to do it in a proper way.
I need help on how to do this process easily and efficiently.
There are two ways to validate a domain in node.js
https.request
Nodejs https module's request method validates the domain provided against the chain of Certificate Authorities root certificate. A code example is given below:
var https = require('https');
var options = {
hostname: 'github.com/',
port: 443,
path: '/',
method: 'GET',
rejectUnauthorized: true
};
var ss;
var req = https.request(options, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
});
req.end();
req.on('error', function(e) {
console.error(e);
});
rejectUnauthorized: This means that it will validate the server/domain certificate against the chain of CA's root certificate.
The only problem with this approach is that this chain should be updated regularly otherwise a new domain that is signed by a certificate authority root certificate which is not part of the chain, marked as an invalid certificate(a common example is a self-signed certificate).
ssl-validate module
It can also be used but it requires another module to get the domain information.

Deploying a Nodejs app to Windows without IIS and without a private key

I've read a tonne of articles on the web and looked at a tonne of questions on stack overflow related to the following, and they all provide basically the same solution which I am unable to implement due to security issues with my company.
I am trying to deploy a NodeJS app to a secure windows server without IIS. I'm not even sure if this is possible - there is very little support about deploying node apps to windows, and what support there is says to use IIS and iisnode together. To add to the complication, my company will not give me the key to the main SSL certificate of the server.
I have access to the server/cert store/certificate, but I can't export its key. Just wondering if there is a way to have server.js point to just the certificate instead of both the certificate AND the key?
I've tried to access the certificate and extract the key via https://www.npmjs.com/package/win-ca but haven't had any luck with this.
I was able to use a self-signed certificate and get everything working, but you need to accept the self-signed certificate in your browser which isn't a viable solution for production.
I've also looked into using nginx, let's encrypt, etc., but windows support for those isn't that great either.
Here is my code which works, but like I said, I need to accept the self-signed cert client side which isn't ideal:
const express = require('express');
const app = express();
const https = require('https');
const http = require('http');
const fs = require('fs');
const options = {
//self-signed cert, I'd rather point this to the main cert for the server
//but I don't have access to the key
key: fs.readFileSync('cert.key'),
cert: fs.readFileSync('cert.pem'),
};
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
app.get('/', function (req, res) {
res.send('Hello World!');
});
In the end I removed all the certificate and security related stuff from my server.js file and just put the website behind a load balancing proxy server.

How to develop a https nodejs web app so that security warning doesn't show

I have changed the protocol on my website to http instead of https.
The following is my code that serves the server.
const https = require('https');
const httpsOptions = {
key : fs.readFileSync('example.key'),
cert : fs.readFileSync('example.crt')
};
https.createServer(httpsOptions, app).listen(port, ()=>{
console.log('server listening at 3000')
});
But now whenever I try to enter my locally run site https://localhost:3000, it shows security warning that the website is not safe anymore.
So I went to google docs https://developers.google.com/web/updates/2016/10/avoid-not-secure-warn to see how to remove the sign and it says 'create the entire website as https' but what I don't understand is all my sites are already https. To see all my views https must be used instead of http.
Is the above code not enough to make all the pages https? if it is, what else do I have to do so that I don't frighten my clients by showing warnings when they enter my site?
Your certificates are probably not signed, especially if you created them yourself, you need to send them to get signed by certified SSL certificated distributers. You can check this blog post for more info on certificate issuers.
Let's Encrypt is a free certificate issuer and you can automate the process of renewing them, so you don't have to worry on that part.

How to access the OpenShift wildcard SSL certificate and private key

On the OpenShift website here: https://help.openshift.com/hc/en-us/articles/202535440-How-do-I-get-SSL-for-my-domains-, it states
You can always take advantage of our *.rhcloud.com wildcard certificate in order
to securely connect to any application via it's original, OpenShift-provided
hostname URL.
However, Node's HTTPS server requires a file path to a certificate and private key in order to use HTTPS:
var privateKey = fs.readFileSync('sslcert/server.key', 'utf8');
var certificate = fs.readFileSync('sslcert/server.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var app = express();
var httpsServer = https.createServer(credentials, app);
httpsServer.listen(443);
None of the OpenShift environment variables (https://www.openshift.com/developers/openshift-environment-variables) appear to be related to SSL certificates, and the documentation does not mention it other than at the above link, which provides no technical information in actually using it.
How do I access the privateKey and certificate file on an OpenShift Node.js gear/cartridge?
It turns out that all SSL certificates are handled by OpenShift routers before they reach the gear/cartridge. There is no need to setup an HttpsServer at all, the normal HttpServer listening on port 8080 will receive both HTTP and HTTPS traffic transparently.
This is true whether you are using a custom certificate or the wildcard certificate, which is pretty nifty.
Nodejs Express application scenario is detailed at OpenShift https answer. To sum up, use the X-Forwarded-Proto header's value from the request headers given to your nodejs web server by openshift's proxy to determine if reply should redirect client to https or is client already requesting on https.

Resources