Force requests over https in Express/Node
Problem
I have a Express.js (v 2.5.8) (node v0.6.12) server running on port 3100. It is front ended by Nginx, which proxies both http and Https requests to port 3100.
I want to force certain urls over https. Here's an example (app is my Express server):
app.get('/applyNow', ensureSec, secure.showApplication );
ensureSec is the function that I'm trying to use to check if connection is over ssl:
function ensureSec(req, res, next) {
if (req.session.ssl == true) {
return next();
} else {
req.session.ssl = true;
res.redirect('https://' + url.parse(req.headers.referer).host +
url.parse(req.url).pathname);
}
}
The redirect works but node (after it times out) throws an error saying `Cannot GET /applyNow
What's the proper way of redirect to ssl?
Solution
As I understand it, you are using nginx to negotiate SSL and proxying both http and https requests to your Express App. I would opt to solve this in nginx instead, if possible, but if nginx can't know which paths should be protected (i.e. only available through https) or you want to do this in your express app for some other reason, here is some information:
You should get the X-Forwarded-Proto
from nginx, set to https
only when the original protocol was https. Here's how you do this in nginx:
proxy_set_header X-Forwarded-Proto https;
I would also forward the Host
header:
proxy_set_header Host $http_host;
In your express app, check for that, or redirect to the host in the headers and the requested path (express parses that to req.path
so you don't have to):
function ensureSec(req, res, next) {
if (req.headers['x-forwarded-proto'] == 'https') {
return next();
} else {
res.redirect('https://' + req.headers.host + req.path);
}
}
Discussion
View additional discussion.