119 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# 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
 | 
						|
 | 
						|
```bash
 | 
						|
npm install --save redirect-https
 | 
						|
```
 | 
						|
 | 
						|
```js
 | 
						|
"use strict";
 | 
						|
 | 
						|
var express = require("express");
 | 
						|
var app = express();
 | 
						|
 | 
						|
var redirector = require("redirect-https")({
 | 
						|
    body: "<!-- Hello Developer! Please use HTTPS instead: {{ URL }} -->"
 | 
						|
});
 | 
						|
 | 
						|
app.use("/", redirector);
 | 
						|
 | 
						|
module.exports = app;
 | 
						|
```
 | 
						|
 | 
						|
## Options
 | 
						|
 | 
						|
```js
 | 
						|
{ 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.
 | 
						|
-   `{{ URL }}` in the body text will be replaced with a URI encoded and HTML escaped url (it'll look just like it is)
 | 
						|
-   `{{ HTML_URL }}` in the body text will be replaced with a URI decoded and HTML escaped url (it'll look just like it would in Chrome's URL bar)
 | 
						|
-   `{{ UNSAFE_URL }}` is the raw, original url
 | 
						|
 | 
						|
## Demo
 | 
						|
 | 
						|
```javascript
 | 
						|
"use strict";
 | 
						|
 | 
						|
var http = require("http");
 | 
						|
var server = http.createServer();
 | 
						|
var securePort = process.argv[2] || 8443;
 | 
						|
var insecurePort = process.argv[3] || 8080;
 | 
						|
 | 
						|
var redirector = require("redirect-https")({
 | 
						|
    port: securePort,
 | 
						|
    body: "<!-- Hello! Please use HTTPS instead: {{ URL }} -->",
 | 
						|
    trustProxy: true // default is false
 | 
						|
});
 | 
						|
 | 
						|
server.on("request", redirector);
 | 
						|
 | 
						|
server.listen(insecurePort, function () {
 | 
						|
    console.log(
 | 
						|
        "Listening on http://localhost.rootprojects.org:" +
 | 
						|
            server.address().port
 | 
						|
    );
 | 
						|
});
 | 
						|
```
 | 
						|
 | 
						|
## 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:
 | 
						|
 | 
						|
```js
 | 
						|
{
 | 
						|
    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).
 | 
						|
 | 
						|
# 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
 | 
						|
<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.rootprojects.org:8080/"><script>alert('hi')</script>`
 | 
						|
-   `http://localhost.rootprojects.org:8080/';URL=http://example.com`
 | 
						|
-   `http://localhost.rootprojects.org:8080/;URL=http://example.com`
 |