Connexion/Redirection automatique HTTPS avec noeud.js / express

j'ai essayé de configurer HTTPS avec un noeud.je travaille sur le projet js. J'ai essentiellement suivi le noeud .js documentation pour cet exemple:

// curl -k https://localhost:8000/
var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello worldn");
}).listen(8000);

Maintenant, quand je fais

curl -k https://localhost:8000/

je reçois

hello world

comme prévu. Mais si je le fais

curl -k http://localhost:8000/

je reçois

curl: (52) Empty reply from server

rétrospectivement, cela semble évident qu'il cela fonctionnerait de cette façon, mais en même temps, les gens qui visitent éventuellement mon projet ne vont pas taper dans https ://yadayada, et je veux que tout le trafic soit https à partir du moment où ils frappent le site.

Comment puis-je obtenir que node (et Express as that is the framework i'm using) transfère tout le trafic entrant à https, qu'il ait été spécifié ou non? Je n'ai pas pu trouver de documentation à ce sujet. Ou est-ce juste suppose que dans un environnement de production, le noeud a quelque chose qui se trouve en face de lui (par exemple nginx) qui gère ce genre de redirection?

c'est ma première incursion dans le développement web, alors s'il vous plaît pardonnez mon ignorance si c'est quelque chose d'évident.

118
demandé sur Jake 2011-09-17 02:15:28

15 réponses

Ryan, merci de m'avoir indiqué la bonne direction. J'ai étoffé votre réponse (2ème paragraphe) un peu avec un peu de code et cela fonctionne. Dans ce scénario, ces extraits de code sont placés dans mon application express:

// set up plain http server
var http = express.createServer();

// set up a route to redirect http to https
http.get('*', function(req, res) {  
    res.redirect('https://' + req.headers.host + req.url);

    // Or, if you don't want to automatically detect the domain name from the request header, you can hard code it:
    // res.redirect('https://example.com' + req.url);
})

// have it listen on 8080
http.listen(8080);

le serveur https express écoute ATM sur 3000. J'ai mis en place ces règles iptables pour que node n'ait pas à s'exécuter en tant que root:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 3000

Tous ensemble, cela fonctionne exactement comme je le voulais.

132
répondu Jake 2017-11-27 00:01:25

si vous suivez les ports conventionnels depuis que HTTP essaye le port 80 par défaut et HTTPS essaye le port 443 par défaut, vous pouvez simplement avoir deux serveurs sur la même machine .: Voici le code:

var https = require('https');

var fs = require('fs');
var options = {
    key: fs.readFileSync('./key.pem'),
    cert: fs.readFileSync('./cert.pem')
};

https.createServer(options, function (req, res) {
    res.end('secure!');
}).listen(443);

// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

Test avec https:

$ curl https://127.0.0.1 -k
secure!

avec http:

$ curl http://127.0.0.1 -i
HTTP/1.1 301 Moved Permanently
Location: https://127.0.0.1/
Date: Sun, 01 Jun 2014 06:15:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked

plus de détails: NodeJS HTTP et HTTPS sur le même port

84
répondu basarat 2017-05-23 11:54:47

avec Nginx vous pouvez profiter de l'en-tête" X-forwarded-proto":

function ensureSec(req, res, next){
    if (req.headers["x-forwarded-proto"] === "https"){
       return next();
    }
    res.redirect("https://" + req.headers.host + req.url);  
}
20
répondu ccyrille 2017-06-22 01:25:33

grâce à ce type: https://www.tonyerwin.com/2014/09/redirecting-http-to-https-with-nodejs.html

app.use (function (req, res, next) {
        if (req.secure) {
                // request was via https, so do no special handling
                next();
        } else {
                // request was via http, so redirect to https
                res.redirect('https://' + req.headers.host + req.url);
        }
});
17
répondu Jeremias Binder 2018-03-08 15:31:50

à partir du 0.4.12, nous n'avons pas de façon très claire D'écouter HTTP & HTTPS sur le même port en utilisant les serveurs HTTP/HTTPS de Node.

certaines personnes ont résolu ce problème en ayant le serveur HTTPS de Node (cela fonctionne avec Express.js) écouter 443 (ou un autre port) et aussi d'avoir un petit serveur http se lier à 80 et rediriger les utilisateurs vers le port sécurisé.

si vous devez absolument être capable de gérer les deux protocoles sur un seul port, alors vous devez mettre nginx, lighttpd, apache, ou un autre serveur web sur ce port et avoir agir comme un mandataire inverse pour le noeud.

12
répondu Ryan Olds 2011-09-16 23:08:15

cette réponse doit être mise à jour pour fonctionner avec Express 4.0. Voici comment j'ai obtenu le serveur http séparé pour fonctionner:

var express = require('express');
var http = require('http');
var https = require('https');

// Primary https app
var app = express()
var port = process.env.PORT || 3000;
app.set('env', 'development');
app.set('port', port);
var router = express.Router();
app.use('/', router);
// ... other routes here
var certOpts = {
    key: '/path/to/key.pem',
    cert: '/path/to/cert.pem'
};
var server = https.createServer(certOpts, app);
server.listen(port, function(){
    console.log('Express server listening to port '+port);
});


// Secondary http app
var httpApp = express();
var httpRouter = express.Router();
httpApp.use('*', httpRouter);
httpRouter.get('*', function(req, res){
    var host = req.get('Host');
    // replace the port in the host
    host = host.replace(/:\d+$/, ":"+app.get('port'));
    // determine the redirect destination
    var destination = ['https://', host, req.url].join('');
    return res.redirect(destination);
});
var httpServer = http.createServer(httpApp);
httpServer.listen(8080);
8
répondu NoBrainer 2014-04-25 02:29:11

je trouve req.le protocole fonctionne quand j'utilise express (n'ont pas testé sans mais je soupçonne qu'il fonctionne). en utilisant le noeud courant 0.10.22 avec express 3.4.3

app.use(function(req,res,next) {
  if (!/https/.test(req.protocol)){
     res.redirect("https://" + req.headers.host + req.url);
  } else {
     return next();
  } 
});
5
répondu Catalyst 2013-11-22 11:23:27

la plupart des réponses ici suggèrent d'utiliser le req.tête.en-tête d'hôte.

L'en-tête Host est requis par HTTP 1.1, mais il est en fait facultatif puisque l'en-tête peut ne pas être envoyé par un client HTTP, et node/express acceptera cette requête.

vous pourriez vous demander: quel client HTTP (E. g: browser) peut envoyer une requête sans cet en-tête? Le protocole HTTP est très trivial. Vous pouvez créer une requête HTTP en quelques lignes de code, pour ne pas envoyer d'hôte en-tête, et si à chaque fois que vous recevez une requête malformée vous lancez une exception, et selon la façon dont vous gérez de telles exceptions, cela peut faire tomber votre serveur.

So toujours valider toutes les entrées . Ce n'est pas de la paranoïa, j'ai reçu des requêtes sans l'en-tête host dans mon service.

Aussi, ne jamais traiter les Url comme des chaînes de caractères . Utilisez le module d'url de noeud pour modifier des parties spécifiques d'une chaîne. Traiter les URLs comme les cordes peuvent être exploitées de nombreuses façons. Ne pas le faire.

3
répondu arboreal84 2016-07-28 18:05:22

vous pouvez utiliser le module "net" pour écouter HTTP & HTTPS sur le même port

var https = require('https');
var http = require('http');
var fs = require('fs');

var net=require('net');
var handle=net.createServer().listen(8000)

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}).listen(handle);

http.createServer(function(req,res){
  res.writeHead(200);
  res.end("hello world\n");
}).listen(handle)
3
répondu luofei614 2017-09-11 07:39:20
var express = require('express');
var app = express();

app.get('*',function (req, res) {
    res.redirect('https://<domain>' + req.url);
});

app.listen(80);

C'est ce que nous utilisons et cela fonctionne très bien!

2
répondu Nick Kotenberg 2015-11-03 19:04:50

si votre application est derrière un proxy de confiance (par exemple un Elbe AWS ou un nginx correctement configuré), ce code devrait fonctionner:

app.enable('trust proxy');
app.use(function(req, res, next) {
    if (req.secure){
        return next();
    }
    res.redirect("https://" + req.headers.host + req.url);
});

Notes:

  • cela suppose que vous hébergez votre site sur 80 et 443, sinon, vous aurez besoin de changer le port lorsque vous redirigez
  • cela suppose aussi que vous supprimez le SSL sur le proxy. Si vous faites SSL de bout en bout, utilisez la réponse de @basarat ci-dessus. Fin pour fin SSL est la meilleure solution.
  • app.enable ('Trust proxy') permet à express de vérifier L'en-tête X-Forwarded-Proto
2
répondu Jamie McCrindle 2016-10-09 10:08:49

cela a fonctionné pour moi:

app.use(function(req,res,next) {
    if(req.headers["x-forwarded-proto"] == "http") {
        res.redirect("https://[your url goes here]" + req.url, next);
    } else {
        return next();
    } 
});
2
répondu Shummy1991 2017-06-12 19:40:46

vous pouvez instancier 2 noeud.serveurs js-un pour HTTP et HTTPS

vous pouvez également définir une fonction de configuration que les deux serveurs exécuteront, de sorte que vous n'ayez pas à écrire beaucoup de code dupliqué.

Voici comment je l'ai fait: (en utilisant restify.js, mais ça devrait marcher pour express.js, ou le nœud lui-même trop)

http://qugstart.com/blog/node-js/node-js-restify-server-with-both-http-and-https /

1
répondu awaage 2012-02-28 23:01:35

j'utilise la solution proposée par Basarat mais je dois aussi réécrire le port car j'avais 2 ports différents pour les protocoles HTTP et HTTPS.

res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });

je préfère aussi utiliser un port non standard pour démarrer nodejs sans privilèges root. J'aime 8080 et 8443 parce que je viens de beaucoup d'années de programmation sur tomcat.

mon dossier complet devient

    var fs = require('fs');
var http = require('http');
var http_port    =   process.env.PORT || 8080; 
var app = require('express')();

// HTTPS definitions
var https = require('https');
var https_port    =   process.env.PORT_HTTPS || 8443; 
var options = {
   key  : fs.readFileSync('server.key'),
   cert : fs.readFileSync('server.crt')
};

app.get('/', function (req, res) {
   res.send('Hello World!');
});

https.createServer(options, app).listen(https_port, function () {
   console.log('Magic happens on port ' + https_port); 
});

// Redirect from http port to https
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
    console.log("http request, will go to >> ");
    console.log("https://" + req.headers['host'].replace(http_port,https_port) + req.url );
    res.end();
}).listen(http_port);

alors j'utilise iptable pour forwording 80 et 443 sur mes ports HTTP et HTTPS.

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8443
1
répondu Lorenzo Eccher 2017-10-20 15:24:50

vous pouvez utiliser le express-force-https module:

npm install --save express-force-https

var express = require('express');
var secure = require('express-force-https');

var app = express();
app.use(secure);
0
répondu Mateus Dal Bianco 2018-02-22 20:52:45