web-dev-qa-db-fra.com

Heroku NodeJS http vers https ssl redirection forcée

J'ai une application en marche sur heroku avec express sur noeud avec https ,. Comment identifier le protocole pour forcer une redirection vers https avec nodejs sur heroku?

Mon application n'est qu'un simple serveur http, elle ne réalise pas (encore) que Heroku lui envoie des requêtes https

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

La solution consiste à utiliser l'en-tête de 'x-forwarded-proto' que Heroku transmet de la même manière que son mandataire proxy. (note latérale: Ils transmettent aussi plusieurs autres variables x qui pourraient être utiles, vérifiez-les ).

Mon code:

/* 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 */
})

Merci Brandon, attendais ce délai de 6 heures qui ne me permettait pas de répondre à ma propre question.

92
Derek Bredensteiner

À compter d'aujourd'hui, le {10 octobre 2014}, en utilisant pile de cèdres Heroku et ExpressJS ~ 3.4.4, voici un ensemble de code fonctionnel. 

La principale chose à retenir ici est que nous déployons à Heroku. La terminaison SSL a lieu au niveau de l'équilibreur de charge, avant que le trafic crypté n'atteigne votre application de nœud. Il est possible de tester si https a été utilisé pour effectuer la demande avec req.headers ['x-forwarded-proto'] === 'https'.

Nous n'avons pas besoin de nous inquiéter d'avoir des certificats SSL locaux dans l'application, comme vous pourriez le faire si vous hébergez dans d'autres environnements. Cependant, vous devriez d'abord appliquer un add-on SSL via les add-ons Heroku si vous utilisez votre propre certificat, vos sous-domaines, etc.

Ensuite, ajoutez ce qui suit pour faire la redirection à partir de n’importe quoi autre que HTTPS vers HTTPS. Ceci est très proche de la réponse acceptée ci-dessus, mais: 

  1. Vous assure d'utiliser "app.use" (pour toutes les actions, pas seulement pour obtenir)
  2. Externalise explicitement la logique forceSsl dans une fonction déclarée
  3. N'utilise pas '*' avec "app.use" - cela a échoué lorsque I testé 
  4. Ici, je ne veux que SSL en production. (Changer selon vos besoins)

Code:

 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...
}

Remarque pour les utilisateurs de SailsJS (0.10.x). Vous pouvez simplement créer une politique (enforceSsl.js) dans api/policies:

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();
  }
};

Ensuite, faites référence à config/policies.js avec toute autre politique, par exemple:

'*': ['authentifié', 'enforceSsl']

98
arcseldon

La réponse acceptée contient un domaine codé en dur, ce qui n'est pas si bon si vous avez le même code dans plusieurs domaines (par exemple: dev-yourapp.com, test-yourapp.com, yourapp.com).

Utilisez ceci à la place:

/* 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

J'ai écrit un module de petit nœud qui applique SSL sur les projets express. Cela fonctionne aussi bien dans les situations standard que dans les proxies inversés (Heroku, nodejitsu, etc.)

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

16
florian

Si vous souhaitez tester l'en-tête x-forwarded-proto sur votre hôte local, vous pouvez utiliser nginx pour configurer un fichier vhost qui envoie toutes les demandes à votre application de noeud. Votre fichier de configuration nginx vhost pourrait ressembler à ceci

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;
  }
}

Les éléments importants ici sont que vous soumettez toutes les demandes au serveur localhost 3000 (c'est ici que votre application de noeud s'exécute) et que vous configurez plusieurs en-têtes, dont X-Forwarded-Proto.

Puis, dans votre application, détectez cet en-tête comme d'habitude

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
})

Les hôtes

Enfin, vous devez ajouter cette ligne à votre fichier hosts

127.0.0.1 dummy.com
6
simo

Si vous utilisez cloudflare.com en tant que CDN en combinaison avec heroku, vous pouvez activer la redirection automatique SSL automatiquement dans cloudflare comme suit:

  1. Connectez-vous et accédez à votre tableau de bord

  2. Sélectionner les règles de la page

    Select Page Rules

  3. Ajoutez votre domaine, par exemple www.example.com et utilisez toujours https sur on Switch always use https to on
4
Ben Marten

Les utilisateurs en boucle peuvent utiliser une version légèrement adaptée de arcseldon answer comme middleware:

serveur/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();
    };
 };

serveur/serveur.js

var forceSSL = require('./middleware/forcessl.js');
app.use(forceSSL());
3
Bunker

Vous devriez jeter un oeil à heroku-ssl-redirect . Il fonctionne comme un charme!

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

Vérifier le protocole dans l'en-tête X-Forwarded-Proto fonctionne bien sur Heroku, comme l'a souligné Derek. Pour ce que ça vaut, voici un Gist du middleware Express que j’utilise et de son test correspondant.

0
Peter Marklund

Une façon plus expressive de le faire.

  app.enable('trust proxy');
  app.use('*', (req, res, next) => {
    if (req.secure) {
      return next();
    }
    res.redirect(`https://${req.hostname}${req.url}`);
  });
0
denixtry
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
Chiedo