Heroku NodeJS http a https ssl redirección forzada


Tengo una aplicación en funcionamiento en heroku con express on node con https,. ¿Cómo puedo identificar el protocolo para forzar una redirección a https con nodejs en heroku?

Mi aplicación es solo un simple servidor http, no se da cuenta (todavía) de que heroku le está enviando solicitudes https:

/* Heroku provides the port they want you on in this environment variable (hint: it's not 80) */
app.listen(process.env.PORT || 3000);
Author: Derek Bredensteiner, 2011-08-25

11 answers

A partir de hoy, 10 de octubre de 2014, usando Heroku Cedar stack, y ExpressJS ~3.4.4, aquí hay un conjunto de código de trabajo.

Lo principal a recordar aquí es que nos estamos desplegando a Heroku. La terminación SSL ocurre en el balanceador de carga, antes de que el tráfico cifrado llegue a su aplicación node. Es posible probar si se usó https para hacer la solicitud con req.headers ['x-forwarded-proto'] = = = 'https' .

No necesitamos preocuparnos con tener certificados SSL locales dentro de la aplicación, etc., como lo haría si se alojara en otros entornos. Sin embargo, primero debe obtener un complemento SSL aplicado a través de Complementos Heroku si usa su propio certificado, subdominios, etc.

Luego simplemente agregue lo siguiente para hacer el redireccionamiento de cualquier otra cosa que no sea HTTPS a HTTPS. Esto está muy cerca de la respuesta aceptada arriba, pero:

  1. Se asegura de que utilice " aplicación.use" (para todas las acciones, no solo get)
  2. Externaliza explícitamente la lógica forceSsl en una función declarada
  3. No usa ' * ' con " app.usar " - esto realmente falló cuando lo probé.
  4. Aquí, solo quiero SSL en producción. (Cambiar según sus necesidades)

Código:

 var express = require('express'),
   env = process.env.NODE_ENV || 'development';

 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.configure(function () {

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

    // other configurations etc for express go here...
}

Nota para SailsJS (0.10.x) usuarios. Simplemente puede crear una política (enforceSsl.js) dentro de api / políticas:

module.exports = function (req, res, next) {
  'use strict';
  if ((req.headers['x-forwarded-proto'] !== 'https') && (process.env.NODE_ENV === 'production')) {
    return res.redirect([
      'https://',
      req.get('Host'),
      req.url
    ].join(''));
  } else {
    next();
  }
};

Luego referencia desde config/policies.js along with any other policies, e. g:

'*': ['autenticado', 'enforceSsl']

 94
Author: arcseldon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-14 14:49:48

La respuesta es usar el encabezado de 'x-forwarded-proto' que Heroku pasa hacia adelante como lo hace su proxy thingamabob. (nota al margen: Pasan varias otras variables x también que pueden ser útiles, échales un vistazo).

Mi código:

/* At the top, with other redirect methods before other routes */
app.get('*',function(req,res,next){
  if(req.headers['x-forwarded-proto']!='https')
    res.redirect('https://mypreferreddomain.com'+req.url)
  else
    next() /* Continue to other routes if we're not redirecting */
})

Gracias Brandon, estaba esperando esa cosa de 6 horas de retraso que no me dejaba responder a mi propia pregunta.

 92
Author: Derek Bredensteiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-03 13:57:56

La respuesta aceptada tiene un dominio hardcoded en ella, que no es demasiado bueno si usted tiene el mismo código en varios dominios (por ejemplo: dev-yourapp.com, test-yourapp.com, yourapp.com).

Usa esto en su lugar:

/* Redirect http to https */
app.get('*', function(req,res,next) {
  if(req.headers['x-forwarded-proto'] != 'https' && process.env.NODE_ENV === 'production')
    res.redirect('https://'+req.hostname+req.url)
  else
    next() /* Continue to other routes if we're not redirecting */
});

Https://blog.mako.ai/2016/03/30/redirect-http-to-https-on-heroku-and-node-generally/

 20
Author: Joan-Diego Rodriguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-26 15:44:24

He escrito un pequeño módulo de nodo que impone SSL en proyectos express. Funciona tanto en situaciones estándar como en caso de proxies inversos (Heroku, nodejitsu, etc.).)

Https://github.com/florianheinemann/express-sslify

 15
Author: florian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-23 01:05:04

Si desea probar el encabezado x-forwarded-proto en su localhost, puede usar nginx para configurar un archivo vhost que proxy todas las solicitudes a su aplicación node. Su archivo de configuración nginx vhost podría tener este aspecto

NginX

server {
  listen 80;
  listen 443;

  server_name dummy.com;

  ssl on;
  ssl_certificate     /absolute/path/to/public.pem;
  ssl_certificate_key /absolute/path/to/private.pem;

  access_log /var/log/nginx/dummy-access.log;
  error_log /var/log/nginx/dummy-error.log debug;

  # node
  location / {
    proxy_pass http://127.0.0.1:3000/;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Los bits importantes aquí son que está proxy todas las solicitudes al puerto 3000 de localhost (aquí es donde se ejecuta su aplicación de nodo) y está configurando un montón de encabezados que incluyen X-Forwarded-Proto

A continuación, en su aplicación detectar que cabecera como de costumbre

Express

var app = express()
  .use(function (req, res, next) {
    if (req.header('x-forwarded-proto') == 'http') {
      res.redirect(301, 'https://' + 'dummy.com' + req.url)
      return
    }
    next()
  })

Koa

var app = koa()
app.use(function* (next) {
  if (this.request.headers['x-forwarded-proto'] == 'http') {
    this.response.redirect('https://' + 'dummy.com' + this.request.url)
    return
  }
  yield next
})

Hosts

Finalmente tienes que añadir esta línea a tu archivo hosts

127.0.0.1 dummy.com
 6
Author: simo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-15 09:29:03

Si está utilizando cloudflare.com como CDN en combinación con heroku, puede habilitar la redirección ssl automática dentro de cloudflare fácilmente de la siguiente manera:

  1. Inicie sesión y vaya a su panel

  2. Seleccionar Reglas de página

    Seleccionar Reglas de Página

  3. Agregue su dominio, p. ej. www.example.com y cambiar siempre use https a encendido Cambiar siempre usar https a encendido
 4
Author: Ben Marten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-18 01:36:25

Los usuarios de Loopback pueden usar una versión ligeramente adaptada de arcseldon answer como middleware:

Servidor/middleware/forcessl.js

module.exports = function() {  
  return function forceSSL(req, res, next) {
    var FORCE_HTTPS = process.env.FORCE_HTTPS || false;
      if (req.headers['x-forwarded-proto'] !== 'https' && FORCE_HTTPS) {
        return res.redirect(['https://', req.get('Host'), req.url].join(''));
      }
      next();
    };
 };

Servidor/Servidor.js

var forceSSL = require('./middleware/forcessl.js');
app.use(forceSSL());
 3
Author: Bunker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-13 15:13:36

Deberías echar un vistazo a heroku-ssl-redirect. Funciona como un encanto!

var sslRedirect = require('heroku-ssl-redirect');
var express = require('express');
var app = express();

// enable ssl redirect
app.use(sslRedirect());

app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);
 2
Author: Julien Le Coupanec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-03 01:32:54

Comprobar el protocolo en la cabecera X-Forwarded-Proto funciona bien en Heroku, tal como Derek ha señalado. Por si sirve de algo, aquí hay un resumen del middleware Express que uso y su prueba correspondiente.

 0
Author: Peter Marklund,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-20 19:27:12
app.all('*',function(req,res,next){
  if(req.headers['x-forwarded-proto']!='https') {
    res.redirect(`https://${req.get('host')}`+req.url);
  } else {
    next(); /* Continue to other routes if we're not redirecting */
  }
});
 0
Author: Chiedo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-01 17:04:13

Una forma más expresa y específica de hacer esto.

  app.enable('trust proxy');
  app.use('*', (req, res, next) => {
    if (req.secure) {
      return next();
    }
    res.redirect(`https://${req.hostname}${req.url}`);
  });
 0
Author: denixtry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-03 05:05:33