Encrypting content sent with Node.js - node.js

I am trying to get HTTPS up on my node.js application. I made progress on this by creating certAccess group that contains both root and ec2-user, and then saying sudo chown ec2-user.certAccess /etc/pki/tls/private/serverKey.key. However, when I run this dummy code:
var fs = require('fs');
var https = require('https');
var app = require('express')();
var options = {
key : fs.readFileSync('/etc/pki/tls/private/serverKey.key').toString(),
cert : fs.readFileSync('/etc/pki/tls/certs/2_mikewarren.me.crt').toString()
};
app.get('/', function (req, res) {
res.send('Hello World!');
});
https.createServer(options, app).listen(8080, function () {
console.log(JSON.stringify(options, null, '\t'));
console.log('Started!');
});
and test it out in my browser (use <yourDomain>:8080), I get no response from server.
I go in and see the permissions of my private key and certificate, and see this:
The private key and certificate configuration, located in /etc/httpd/conf.d/ssl.conf looks like:
However, when I do the test in my browser (even typing https:// in front of the URL, which I shouldn't have to), I get no response from server.
What should I do?!?!?

I came up with solution. Here's what I did:
I added ca member to options and pointed to that chain cert as it, like this: ca : fs.readFileSync('/etc/pki/tls/certs/1_root_bundle.crt', 'utf8'). That solves the cert problem. As for the next part, I simply wrote line in BASH that redirects https (port 443) to the port I was using (which I, out of convenience, changed to 8443, because I already redirected http to 8080).
That got it working, but it still sucks that I have to still prefix URL with https://. I shouldn't have to! I think solution to that is to do what I already have done, but redirect http to port 8443, or proxy port 8080 to port 8443.

Related

How to automatically reload updated SSL certificates in Node.js Application

I created nodejs application and I'm using Lets Encrypt SSL certificates. Following is my Code
var express = require(‘express’);
var https = require(‘https’);
var fs = require(‘fs’);
var option = {
key: fs.readFileSync(‘/etc/letsencrypt/live/$DOMAIN/privkey.pem’),
cert: fs.readFileSync(‘/etc/letsencrypt/live/$DOMAIN/fullchain.pem’)
};
const app = express();
app.use((req, res) =>
{
res.end(‘Hello World’);
});
https.createServer(option, app).listen(8000);
I have used pm2 to start this application using following command
sudo pm2 start app.js --watch
I am updating SSL certificates by using following cronjob
0 8 * * * sudo certbot renew
I want to reload SSL certificates automatically whenever certbot renews SSL certificates. How can I achieve this?
You can use the flag --post-hook to restart your application after every renewal.
certbot renew --post-hook "pm2 restart app_name"
Update #1
Please note that the command we are running is in crontab and any global program has to be referenced with the full path. You can use the which command to find the executable file path for the command.
For those of us who can't afford to or would rather not restart our servers to reload certs and that aren't comfortable with Dylan Landry's SNI-based approach, there has been a purpose-built way of doing this built into node for a while now, via server.setSecureContext (where server is a standard node https server instance). See snippet below:
const app = express();
function readCertsSync() {
return {
key: fs.readFileSync(sslKeyPath),
cert: fs.readFileSync(sslCertPath) + fs.readFileSync(sslFullChainPath)
}
}
let httpd = https.createServer(readCertsSync(), app).listen(port, onReady);
// Refresh httpd's certs when certs change on disk. The timeout stuff
// "ensures" that all 3 relevant files are updated, and accounts for
// sometimes trigger-happy fs.watch.
let waitForCertAndFullChainToGetUpdatedTooTimeout;
fs.watch(sslKeyPath, () => {
clearTimeout(waitForCertAndFullChainToGetUpdatedTooTimeout);
waitForCertAndFullChainToGetUpdatedTooTimeout = setTimeout(() => {
httpd.setSecureContext(readCertsSync());
}, 1000);
});
The fs.watch and timeout code is admittedly a bit clunky and can be improved using something like chokidar and some more expansive logic to monitor the state of all 3 relevant files. I chose to keep things simple to focus on the interesting bit: setSecureContext.
For reference, see https://nodejs.org/api/tls.html#tls_server_setsecurecontext_options
Also, credit goes to nolimitdev who came up with most of this before setSecureContext was even a thing.
You can reload the new certs without restarting your server.
According to the issue Reload certificate files of https.createServer() without restarting node server #15115 , specifically this comment from mscdex:
FWIW you can already do this with SNICallback():
const https = require('https');
const tls = require('tls');
const fs = require('fs');
var ctx = tls.createSecureContext({
key: fs.readFileSync(config.sslKeyPath),
cert: fs.readFileSync(config.sslCrtPath)
});
https.createServer({
SNICallback: (servername, cb) => {
// here you can even change up the `SecureContext`
// based on `servername` if you want
cb(null, ctx);
}
});
With that, all you have to do is re-assign ctx and then it will get used for any future requests.
Using the example above, you just need to do fs.readFileSync again on the cert path from within the SNICallback and attach them to the ctx object. But, you only want to do this when you know they've just changed. You can watch the files from javascript for changes. You can use fs.watch() for that or something from npm.

Accessing node server through url

So I have this script
const hostname = 'localhost';
const port = 2525;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
File named nodeTest.js and I have all this on a webhost where I also have my domain. Now running this script through ssh "node nodeTest.js" creates server and I can access it with another ssh terminal with curl call. I get response "hello world" as I should.
Now the problem is I cannot access it normally through my domain link.. like somethingsomething.com
I also have option to create node application through a cpanel but when I create it i get no response going to specified link
I just started with nodejs so maybe I am missing something obvious. There is also help site on my webhost web that has tutorial how to set this up and I do as they say but i get no console.log msg.
I also tried setting server to 8080 port but I get error already in use.
Would appreciate if someone would point me in the right direction.
I figured it out.. with the help of this site
https://www.a2hosting.com/kb/cpanel/cpanel-software/create-application-with-nodejs-selector
I was missing package.json part

Issue from HTTPS installation in node js

I am using https package for running the program in https. I have proper ssl certificate and private key and bundle file. all these files included in my code. This https program also running without error. But when I connect front end to node js it doesn't connected. The error is "504 gateway Time out". Where is I make error? I host my code in azure.
const https = require('https');
//path for private key and certificate
let privateKey = fs.readFileSync('sslcert/server.key','utf8');
let certificate = fs.readFileSync('sslcert/server.crt','utf8');
var credential = {
key: privateKey,
cert: certificate,
};
var server = https.createServer(credential, app)
server.listen('8443',function() {
console.log('Listening on https://localhost:' + 8443);
});
Refer to this https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
So if you do not declare host for your server.listen() the default host should be 0.0.0.0 instead.
If you need to listen of specific address, you must define it after the port.
http.createServer(function (req, res) {
}).listen(8443, "0.0.0.0");
Your front server need to be on the same network subnet as your API.

How to properly create an HTTPS transparent proxy server with node?

I am using the npm package http-proxy that claims to help with that, however I am totally incapable to make it work. So far I have only success by making an transparent HTTP proxy server, however when it goes to create a transparent HTTPS proxy server then nothing happens.
I am using an Android device configured to use a proxy with the port where the proxy is expecting to be configured, but nothing is triggered in the nodejs side. Only if I have configured an HTTP proxy server then things seems to be working.
This is the code I have for the HTTPS:
var https = require('https');
var fs = require('fs');
var httpProxy = require('http-proxy');
var options = {
key: fs.readFileSync('./client-key.pem', 'utf8'),
cert: fs.readFileSync('./client-cert.pem', 'utf8')
};
var proxy = httpProxy.createProxyServer({
ssl: options
});
https.createServer(options, function (req, res) {
console.log("new", req.url);
proxy.web(req, res, {
target: req.url
});
}).listen(8000);
If I use the createServer from the http package then it works for http calls (as in that the callback is being fired), however it does not for https with these instruction. Anybody knows what am I doing wrong?
PS: I do not care if I have to use a different npm package.
you can use https://www.npmjs.com/package/transparent-proxy
It is built extending native net.createServer. It acts like a REAL transparent http proxy and It allows you, for example, to easy upstream requests to other proxies and make some requests-chaining through multiple proxies... etc...
Install
npm i transparent-proxy
Use
const ProxyServer = require('transparent-proxy');
//init ProxyServer
const server = new ProxyServer();
//starting server on port 8080
server.listen(8080, '0.0.0.0', function () {
console.log('TCP-Proxy-Server started!', server.address());
});
It works on Termux too :)

How to enable SSL connection a NodeJS (Express) based Server

Following is the script I found on NodeJS Official Website:
// curl -k https://localhost:8000/
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
I'm completely new to SSL thing. I read some tutorials on how to enable SSL on Nodejs but still quite not confident with the process.
I have a domain name (Godaddy), SSL (Namecheap) and Cloud Server (Digital Ocean with an application deployed on HTTP prefix).
Whenever I open my Login page of my website, Google Chrome mark it as "Not secure" so I wanted to add SSL to the website.
What things I need to do on the NodeJS server (Express) and what things I need to do on Namecheap? What will be the sequence of doing that? What are cmd lines to generate .pem .csr files?
I'm didn't found and comprehensive guide laying down all the steps in a concise manner so just laid down the steps concisely (if possible) with the links to the resources for further digging.
And also, how can I use express framework to create https server in liue of above script?
That script is correct for setting the certs for your https. If your site is public, as it seems, then you'll want to buy certs from your ssl service, Namecheap in your example. Then you would move them to your host and reference them in the options object in your example. However, you can generate your own ssl certs and that will work as well. Though, any users will be warned that they're not trusted since you self signed/created them. I suggest going with the Namecheap option.
Note: You only have an https server in your example and anyone attempting to access your site via http will receive a blank page. You'll need to also create an http server, via the following:
var http = require('http');
http.createServer(...);
I would suggest having the http server simply redirect to the https url.
My code and error is here:
no such directory found error:
key: fs.readFileSync('../private.key'),
cert: fs.readFileSync('../public.cert')
error, no such directory found
key: fs.readFileSync('./private.key'),
cert: fs.readFileSync('./public.cert')
Working code should be
key: fs.readFileSync(__dirname + '/private.key', 'utf8'),
cert: fs.readFileSync(__dirname + '/public.cert', 'utf8')
Complete https code is:
const https = require('https');
const fs = require('fs');
// readFileSync function must use __dirname get current directory
// require use ./ refer to current directory.
const options = {
key: fs.readFileSync(__dirname + '/private.key', 'utf8'),
cert: fs.readFileSync(__dirname + '/public.cert', 'utf8')
};
// Create HTTPs server.
var server = https.createServer(options, app);
This is my working code for express 4.0.
express 4.0 is very different from 3.0 and others.
4.0 you have /bin/www file, which you are going to add https here.
"npm start" is standard way you start express 4.0 server.
readFileSync() function should use __dirname get current directory
while require() use ./ refer to current directory.
First you put private.key and public.cert file under /bin folder,
It is same folder as WWW file.

Resources