Redirect from HTTP to HTTPS using meta redirects
Go to file
AJ ONeal 16251a99b9 adjust spacing to be easier to read from curl output 2020-04-26 17:31:25 -06:00
.gitignore Initial commit 2015-06-19 09:15:45 -06:00
LICENSE Initial commit 2015-06-19 09:15:45 -06:00
README.md Merge branch 'master' of ssh://git.coolaj86.com:22042/coolaj86/redirect-https.js 2018-10-02 19:07:22 -06:00
example.js option for URI decoded, but still html escaped urls 2015-07-07 17:30:56 -06:00
index.js adjust spacing to be easier to read from curl output 2020-04-26 17:31:25 -06:00
package.json v1.3.0: redirect root '/' with 301 by default (for curl | bash installers) 2018-10-02 18:25:04 -06:00
test.js fix #2 2016-11-21 15:45:05 -07:00

README.md

redirect-https.js

Secure-by-default redirects from HTTP to HTTPS.

  • Browsers get a 301 + Location redirect
  • Only developers, bots, and APIs see security warning (advising to use HTTPS)
  • Always uses meta redirect as a fallback, for everyone
  • '/' always gets a 301 (for curl | bash installers)
  • minimally configurable, don't get fancy

See https://coolaj86.com/articles/secure-your-redirects/

Installation and Usage

npm install --save redirect-https
'use strict';

var express = require('express');
var app = express();

app.use('/', require('redirect-https')({
  body: '<!-- Hello Mr Developer! Please use HTTPS instead -->'
}));

module.exports = app;

Options

{ port: 443           // defaults to 443
, body: ''            // defaults to an html comment to use https
, trustProxy: true    // useful if you haven't set this option in express
, browsers: 301       // issue 301 redirect if the user-agent contains "Mozilla/"
, apis: 'meta'        // issue meta redirects to non-browsers
}
  • This module will call next() if the connection is already tls / https.
  • If trustProxy is true, and X-Forward-Proto is https, next() will be called.
  • If you use {{URL}} in the body text it will be replaced with a URI encoded and HTML escaped url (it'll look just like it is)
  • If you use {{HTML_URL}} in the body text it will be replaced with a URI decoded and HTML escaped url (it'll look just like it would in Chrome's URL bar)

Advanced Options

For the sake of curl | bash installers and the like there is also the option to cause bots and apis (i.e. curl) to get a certain redirect for an exact path match:

{ paths: [
    { match: '/'
    , redirect: 301
    }
  , { match: /^\/$/
    , redirect: 301
    }
  ]
}

If you're using this, you're probably getting too fancy (but hey, I get too fancy sometimes too).

Demo

'use strict';

var http = require('http');
var server = http.createServer();
var securePort = process.argv[2] || 8443;
var insecurePort = process.argv[3] || 8080;

server.on('request', require('redirect-https')({
  port: securePort
, body: '<!-- Hello! Please use HTTPS instead -->'
, trustProxy: true // default is false
}));

server.listen(insecurePort, function () {
  console.log('Listening on http://localhost.pplwink.com:' + server.address().port);
});

Meta redirect by default, but why?

When something is broken (i.e. insecure), you don't want it to kinda work, you want developers to notice.

Using a meta redirect will break requests from curl and api calls from a programming language, but still have all the SEO and speed benefits of a normal 301.

<html><head>
<meta http-equiv="refresh" content="0;URL='https://example.com/foo'" />
</head><body>
<!-- Hello Mr. Developer! Please use https instead. Thank you! -->
</html>

Other strategies

If your application is properly separated between static assets and api, then it would probably be more beneficial to return a 200 OK with an error message inside

Security

The incoming URL is already URI encoded by the browser but, just in case, I run an html escape on it so that no malicious links of this sort will yield unexpected behavior:

  • http://localhost.pplwink.com:8080/"><script>alert('hi')</script>
  • http://localhost.pplwink.com:8080/';URL=http://example.com
  • http://localhost.pplwink.com:8080/;URL=http://example.com