I am trying to create a web server where I can get the certificate from the client/peer as I need to read the SAN and Subject fields. The CA and localhost certificates have been generated using mkcert (I also used openssl) where it adds the CA.crt to the browser and system ca-certificate bundle.
When I start node NODE_TLS_REJECT_UNAUTHORIZED='0' node index.js it immediately gives an authorizationError: SELF_SIGNED_CERT_IN_CHAIN.
Using Chrome when I naviate to the site it reports:
This site can’t provide a secure connectionlocalhost didn’t accept your login certificate, or one may not have been provided.
Try contacting the system admin.
ERR_BAD_SSL_CLIENT_AUTH_CERT
Not sure where I'm going wrong. Any help appreciated!
const fs = require("fs");
const key = fs.readFileSync("./localhost-key.pem");
const cert = fs.readFileSync('./localhost.pem');
const express = require("express");
const app = express();
const router = express.Router();
app.get("/", (req, res, next) => {
const tlsSock = req.socket;
console.log(tlsSock.authorized)
console.log(tlsSock.authorizedError)
console.log(tlsSock.getCertificate());
res.status(200).send("Hello world!");
});
const https = require("https");
const server = https.createServer(
{
key,
cert,
requestCert: true, // Need mTLS so the peer certificate is sent.
},
app
);
var req = https
.request({
url: "https://localhost",
})
.on("error", function (err) {
console.log("err:", err);
})
.on("response", function (res) {
console.log("peerCertificate:", res.socket.getPeerCertificate());
console.log("authorized:", res.socket.authorized);
console.log("authorizationError:", res.socket.authorizationError);
});
req.end();
const port = 3000;
server.listen(port, () => {
console.log(`Server is listening on https://localhost:${port}`);
});
im trying to setup a AlphaSSL WildCard Certificate on a express server on a sub-domain
I'm trying start a blank app on ssl like so:
const options = {
key: fs.readFileSync(__dirname + '/privatekey.pem','utf8'),
cert: fs.readFileSync(__dirname + '/certificate.pem','utf8'),
ca: fs.readFileSync(__dirname + '/intermediate.pem','utf8'),
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.send('Hello World');
}).listen(80);
But the page returns me a ERR_EMPTY_RESPONSE, same if i pass my final app on the createServer, and without the ssl
Probably You do not need to use 'utf8' parameter for SSL keys while reading files. The need to get byte array as content, not a string.
Im trying to run nodejs app to work with my php project. the problem is I think with SSL which is enabled in the server.
I have two files that I found in my root directory after SSL install: domain.com.csr and domain.com.key and I tried to combine them to connection while creating https server, but nothing worked for me.
so far I have this code:
var socket = require('socket.io');
var express = require('express');
var http = require('http');
var app = express();
var server = http.createServer(app);
var io = socket.listen(server);
app.get('/test', function(req, res) {
res.send('hello world');
console.log('visited test')
});
io.sockets.on('connection', function (client) {
console.log("New client !");
client.on('message', function (data) {
console.log('Message received ' + data.name + ":" + data.message);
io.sockets.emit('message', {name: data.name, message: data.message});
});
});
server.listen(8080, function () {
console.log('listen me on: 8080');
});
and it works well when I'm trying to visit http://ip:8080/test so it means that node server is working, but when I try to create socket connection on my view file var socket = io.connect('http://ip:8080'); it gives me error:
The page at 'https://www.domain.com/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://ip:8080/socket.io/?EIO=3&transport=polling&t=1446818946199-0'. This request has been blocked; the content must be served over HTTPS.
so the problem is clear enough, but how to deal with it?
also I have tried this connection:
var socket = io.connect('https://www.domain.com:8080');
but the result is 404 GET Error. How to deal with it?
Update
now the part of code I should use, but don't know how to get cert of existing SSL in the server.
var socket = require('socket.io');
var express = require('express');
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('path/to/key.pem'), // dont have
cert: fs.readFileSync('path/to/cert.cert') // dont have
};
var app = express();
var server = https.createServer(options, app);
var io = socket.listen(server);
app.get('/test', function(req, res) {
res.send('hello world');
console.log('visited test')
});
io.sockets.on('connection', function (client) {
console.log("New client !");
client.on('message', function (data) {
console.log('Message received ' + data.name + ":" + data.message);
io.sockets.emit('message', {name: data.name, message: data.message});
});
});
server.listen(443, function () {
console.log('listen me on: 443');
});
I think you need to contact your certificate authority (the organization that issued your first ssl certificate) and get a copy of the certificate (the path/to/key.pem and path/to/cert.cert) or find the existing keys somewhere on your existing server.
If you're running apache, your configuration file will have a section with values for the paths of the .cert and .pem files labeled SSLCertificateFile and SSLCertificateKeyFile, then just update the paths in your node app to point to them. You also have to make sure that your SSL certificate meets the requirements (for example, needs to be Multi-domain if your node app runs on a different domain, or a Wildcard SSL certificate to run your node app on a subdomain).
The domain.com.csr and domain.com.key files you found are the private key and certificate request used to generate your initial SSL certificate and aren't going to do anything to enable SSL on your node app.
Perhaps I'm not understanding how SSL/HTTPS works (likely), but SalesForce's API requires an https connection in their callback so I'm trying to get my head around it.
Here's how I've set it up in app.js
var http = require('http');
var https = require('https');
var privateKey = fs.readFileSync('private/key.pem', 'utf8');
var certificate = fs.readFileSync('private/cert.pem', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var port = process.env.PORT || 8080;
http.createServer(app).listen(8081);
https.createServer(credentials, app).listen(port);
I'm accessing my local dev environment with localhost:8080, localhost:8080/profile etc.
When I type this into the address bar, I get this error:
Instead, I have to explicitly type "https://" in front of it, then it works.
From looking around SO I've seen some similar questions which suggesting using the middleware:
app.use(function(req, res, next) {
console.log(req.secure);
if(!req.secure) {
var url = ['https://', req.get('Host'), req.url].join('')
console.log(url);
return res.redirect(url);
}
next();
});
However, this doesn't work; if I go to localhost:8080 I'm not redirected anywhere (I get the same error as above), and if I got to localhost:8081 I get redirected to https://localhost:8081 which obviously doesn't work because we need to be on port 8080 for HTTPS.
Any ideas on what I'm doing wrong here? I'd just like to run the whole thing on HTTPS by default.
Given an SSL key and certificate, how does one create an HTTPS service?
The Express API doc spells this out pretty clearly.
Additionally this answer gives the steps to create a self-signed certificate.
I have added some comments and a snippet from the Node.js HTTPS documentation:
var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
// This line is from the Node.js HTTPS documentation.
var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.cert')
};
// Create a service (the app object is just a callback).
var app = express();
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
For Node 0.3.4 and above all the way up to the current LTS (v16 at the time of this edit), https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener has all the example code you need:
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);
Note that if want to use Let's Encrypt's certificates using the certbot tool, the private key is called privkey.pem and the certificate is called fullchain.pem:
const certDir = `/etc/letsencrypt/live`;
const domain = `YourDomainName`;
const options = {
key: fs.readFileSync(`${certDir}/${domain}/privkey.pem`),
cert: fs.readFileSync(`${certDir}/${domain}/fullchain.pem`)
};
Found this question while googling "node https" but the example in the accepted answer is very old - taken from the docs of the current (v0.10) version of node, it should look like this:
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
The above answers are good but with Express and node this will work fine.
Since express create the app for you, I'll skip that here.
var express = require('express')
, fs = require('fs')
, routes = require('./routes');
var privateKey = fs.readFileSync('cert/key.pem').toString();
var certificate = fs.readFileSync('cert/certificate.pem').toString();
// To enable HTTPS
var app = module.exports = express.createServer({key: privateKey, cert: certificate});
The minimal setup for an HTTPS server in Node.js would be something like this :
var https = require('https');
var fs = require('fs');
var httpsOptions = {
key: fs.readFileSync('path/to/server-key.pem'),
cert: fs.readFileSync('path/to/server-crt.pem')
};
var app = function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}
https.createServer(httpsOptions, app).listen(4433);
If you also want to support http requests, you need to make just this small modification :
var http = require('http');
var https = require('https');
var fs = require('fs');
var httpsOptions = {
key: fs.readFileSync('path/to/server-key.pem'),
cert: fs.readFileSync('path/to/server-crt.pem')
};
var app = function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}
http.createServer(app).listen(8888);
https.createServer(httpsOptions, app).listen(4433);
Update
Use Let's Encrypt via Greenlock.js
Original Post
I noticed that none of these answers show that adding a Intermediate Root CA to the chain, here are some zero-config examples to play with to see that:
https://github.com/solderjs/nodejs-ssl-example
http://coolaj86.com/articles/how-to-create-a-csr-for-https-tls-ssl-rsa-pems/
https://github.com/solderjs/nodejs-self-signed-certificate-example
Snippet:
var options = {
// this is the private key only
key: fs.readFileSync(path.join('certs', 'my-server.key.pem'))
// this must be the fullchain (cert + intermediates)
, cert: fs.readFileSync(path.join('certs', 'my-server.crt.pem'))
// this stuff is generally only for peer certificates
//, ca: [ fs.readFileSync(path.join('certs', 'my-root-ca.crt.pem'))]
//, requestCert: false
};
var server = https.createServer(options);
var app = require('./my-express-or-connect-app').create(server);
server.on('request', app);
server.listen(443, function () {
console.log("Listening on " + server.address().address + ":" + server.address().port);
});
var insecureServer = http.createServer();
server.listen(80, function () {
console.log("Listening on " + server.address().address + ":" + server.address().port);
});
This is one of those things that's often easier if you don't try to do it directly through connect or express, but let the native https module handle it and then use that to serve you connect / express app.
Also, if you use server.on('request', app) instead of passing the app when creating the server, it gives you the opportunity to pass the server instance to some initializer function that creates the connect / express app (if you want to do websockets over ssl on the same server, for example).
To enable your app to listen for both http and https on ports 80 and 443 respectively, do the following
Create an express app:
var express = require('express');
var app = express();
The app returned by express() is a JavaScript function. It can be be passed to Node’s HTTP servers as a callback to handle requests. This makes it easy to provide both HTTP and HTTPS versions of your app using the same code base.
You can do so as follows:
var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
var app = express();
var options = {
key: fs.readFileSync('/path/to/key.pem'),
cert: fs.readFileSync('/path/to/cert.pem')
};
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
For complete detail see the doc
You can use also archive this with the Fastify framework:
const { readFileSync } = require('fs')
const Fastify = require('fastify')
const fastify = Fastify({
https: {
key: readFileSync('./test/asset/server.key'),
cert: readFileSync('./test/asset/server.cert')
},
logger: { level: 'debug' }
})
fastify.listen(8080)
(and run openssl req -nodes -new -x509 -keyout server.key -out server.cert to create the files if you need to write tests)
If you need it only locally for local development, I've created utility exactly for this task - https://github.com/pie6k/easy-https
import { createHttpsDevServer } from 'easy-https';
async function start() {
const server = await createHttpsDevServer(
async (req, res) => {
res.statusCode = 200;
res.write('ok');
res.end();
},
{
domain: 'my-app.dev',
port: 3000,
subdomains: ['test'], // will add support for test.my-app.dev
openBrowser: true,
},
);
}
start();
It:
Will automatically add proper domain entries to /etc/hosts
Will ask you for admin password only if needed on first run / domain change
Will prepare https certificates for given domains
Will trust those certificates on your local machine
Will open the browser on start pointing to your local server https url
Download rar file for openssl set up from here: https://indy.fulgan.com/SSL/openssl-0.9.8r-i386-win32-rev2.zip
Just copy your folder in c drive.
Create openssl.cnf file and download their content from : http://web.mit.edu/crypto/openssl.cnf
openssl.cnf can be put any where but path shoud be correct when we give in command prompt.
Open command propmt and set openssl.cnf path C:\set OPENSSL_CONF=d:/openssl.cnf
5.Run this in cmd : C:\openssl-0.9.8r-i386-win32-rev2>openssl.exe
Then Run OpenSSL> genrsa -des3 -out server.enc.key 1024
Then it will ask for pass phrases : enter 4 to 11 character as your password for certificate
Then run this Openssl>req -new -key server.enc.key -out server.csr
Then it will ask for some details like country code state name etc. fill it freely.
10 . Then Run Openssl > rsa -in server.enc.key -out server.key
Run this OpenSSL> x509 -req -days 365 -in server.csr -signkey server.key -out server.crt then use previous code that are on stack overflow
Thanks