with tls nodejs node node.js https express

node.js - nodejs - tls with node



Conexión HTTPS automática/redirección con node.js/express (15)

He intentado configurar HTTPS con un proyecto node.js en el que estoy trabajando. En esencia, he seguido la documentación de node.js para este ejemplo:

// 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 world/n"); }).listen(8000);

Ahora, cuando lo haga

curl -k https://localhost:8000/

yo obtengo

hello world

como se esperaba. Pero si lo hago

curl -k http://localhost:8000/

yo obtengo

curl: (52) Empty reply from server

En retrospectiva, parece obvio que funcionaría de esta manera, pero al mismo tiempo, las personas que finalmente visiten mi proyecto no van a escribir https : // yadayada, y quiero que todo el tráfico sea https desde el momento en que golpean el sitio.

¿Cómo puedo obtener el nodo (y Express, ya que ese es el marco que estoy usando) para transferir todo el tráfico entrante a https, independientemente de si se especificó o no? No he podido encontrar ninguna documentación que haya abordado esto. ¿O simplemente se supone que en un entorno de producción, el nodo tiene algo que se encuentra frente a él (por ejemplo, nginx) que maneja este tipo de redirección?

Esta es mi primera incursión en el desarrollo web, así que por favor perdone mi ignorancia si esto es algo obvio.


A partir de 0.4.12, no tenemos una forma realmente limpia de escuchar HTTP y HTTPS en el mismo puerto utilizando los servidores HTTP / HTTPS de Node.

Algunas personas han resuelto este problema al tener el servidor HTTPS de Node (esto también funciona con Express.js) escuchan 443 (o algún otro puerto) y también tienen un servidor HTTP pequeño que se vincula a 80 y redirige a los usuarios al puerto seguro.

Si tiene que ser capaz de manejar ambos protocolos en un solo puerto, debe colocar nginx, lighttpd, apache o algún otro servidor web en ese puerto y actuar como un proxy inverso para Node.


Con Nginx puede aprovechar el encabezado "x-forward-proto":

function ensureSec(req, res, next){ if (req.headers["x-forwarded-proto"] === "https"){ return next(); } res.redirect("https://" + req.headers.host + req.url); }


Encuentro que req.protocol funciona cuando uso Express (no lo he probado pero sospecho que funciona). utilizando el nodo actual 0.10.22 con 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(); } });


Esta respuesta debe actualizarse para que funcione con Express 4.0. Así es como obtuve el servidor http por separado para trabajar:

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


Esto funcionó para mí:

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



La mayoría de las respuestas aquí sugieren usar el encabezado req.headers.host.

El HTTP 1.1 requiere el encabezado Host, pero en realidad es opcional, ya que un cliente HTTP no puede enviar realmente el encabezado, y node / express aceptará esta solicitud.

Puede preguntar: ¿qué cliente HTTP (por ejemplo, el navegador) puede enviar una solicitud que falta ese encabezado? El protocolo HTTP es muy trivial. Puede crear una solicitud HTTP en pocas líneas de código, para no enviar un encabezado de host, y si cada vez que recibe una solicitud mal formada lanza una excepción, y dependiendo de cómo maneje tales excepciones, esto puede demorar su servidor.

Por lo tanto, siempre valide todas las entradas . Esto no es paranoia, he recibido solicitudes que carecen del encabezado de host en mi servicio.

Además, nunca trate las URL como cadenas . Use el módulo url del nodo para modificar partes específicas de una cadena. El tratamiento de URL como cadenas se puede aprovechar de muchas maneras. No lo hagas



Puede usar el módulo de express-force-https :

npm install --save express-force-https

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


Ryan, gracias por apuntarme en la dirección correcta. Completé tu respuesta (2 ° párrafo) un poco con un poco de código y funciona. En este escenario, estos fragmentos de código se ponen en mi aplicación 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);

El servidor de https express escucha ATM en 3000. Configuré estas reglas de iptables para que el nodo no tenga que ejecutarse como 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

Todos juntos, esto funciona exactamente como yo quería.


Si sigue los puertos convencionales, ya que HTTP intenta el puerto 80 de manera predeterminada y HTTPS prueba el puerto 443 de forma predeterminada, puede simplemente tener dos servidores en la misma máquina: aquí está el código:

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

Prueba con https:

$ curl https://127.0.0.1 -k secure!

Con 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

Más detalles: Nodejs HTTP y HTTPS en el mismo puerto


Si su aplicación está detrás de un proxy de confianza (por ejemplo, un ELB de AWS o un nginx configurado correctamente), este código debería funcionar:

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

Notas:

  • Esto supone que está alojando su sitio en 80 y 443, de lo contrario, tendrá que cambiar el puerto cuando redirija
  • Esto también asume que estás terminando el SSL en el proxy. Si está haciendo SSL de extremo a extremo, use la respuesta de @basarat anterior. End to end SSL es la mejor solución.
  • app.enable (''trust proxy'') permite que express compruebe el encabezado X-Forwarded-Proto

Utilizo la solución propuesta por Basarat pero también necesito sobrevolver el puerto porque solía tener 2 puertos diferentes para protocolos HTTP y HTTPS.

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

También prefiero usar el puerto no estándar para iniciar nodejs sin privilegios de root. Me gustan 8080 y 8443 porque vengo de muchos años de programación en tomcat.

Mi archivo completo se convierte

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

Luego utilizo iptable para escribir el tráfico 80 y 443 en mis puertos HTTP y 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


puede usar el módulo "net" para escuchar HTTP y HTTPS en el mismo puerto

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)


var express = require(''express''); var app = express(); app.get(''*'',function (req, res) { res.redirect(''https://<domain>'' + req.url); }); app.listen(80);

¡Esto es lo que usamos y funciona genial!