Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTTPS redirection only works when page is reloaded

I have installed a SSL certificate on my page, which runs a Node.js + Express application, configured the Express server to always force redirection to HTTPs and everything works fine, except that the https redirection only works when the page is reloaded or when the Enter key is pressed again. I recorded a gif to show what happens:

http://recordit.co/uBiW3bcQCM

And here's my Express configuration.

var express = require('express');
var path = require('path');
var serveStatic = require('serve-static');

var forceSsl = function (req, res, next) {
  if (req.headers['x-forwarded-proto'] !== 'https') {
    return res.redirect(['https://', req.get('Host'), req.url].join(''));
  }
  return next();
};

app = express();
app.use(serveStatic(__dirname));

if(process.env.NODE_ENV === 'production') {
  app.use(forceSsl);
}

app.all('/*', function(req, res) {
  res.sendfile('index.html');
});

var port = process.env.PORT || 5000;
app.listen(port);

console.log('server started '+ port);

My application runs on Heroku. Can anyone help me finding out what's happening?

Thanks in advance.

like image 416
felipeecst Avatar asked Jul 26 '17 21:07

felipeecst


Video Answer


2 Answers

I think your server is sending the content before sending the redirection headers.

If you swap:

app.use(serveStatic(__dirname));
app.use(forceSsl);

for:

app.use(forceSsl);
app.use(serveStatic(__dirname));

It seems to work much better!

The reason why your browser did perform the redirection on reload/enter is obscure to me as I could not reproduce the behavior. On FF I was never redirected.

It might be due to the request headers being different, such as a HEAD, instead of a GET, or something else. I could not investigate more on that, use Wireshark or Burpsuite to know exactly what happens, if that still matters...

like image 133
Fabien Avatar answered Sep 21 '22 13:09

Fabien


This redirectToHTTPS() middleware should work for you. It will redirect to https site even when the user does not provide prefix. Add X-Forwarded-Port for identifying the port used for https site.

function redirectToHTTPS () {
  return function middlewareRedirectToHTTPS (req, res, next) {
    const isNotSecure = (!req.get('x-forwarded-port') && req.protocol !== 'https') ||
      parseInt(req.get('x-forwarded-port'), 10) !== 443
    if (isNotSecure) {
      return res.redirect('https://' + req.get('host') + req.url)
    }
    next()
}
}
like image 34
Bharathvaj Ganesan Avatar answered Sep 18 '22 13:09

Bharathvaj Ganesan