Abilitazione di HTTPS su express.js


408

Sto cercando di far funzionare HTTPS su express.js per il nodo e non riesco a capirlo.

Questo è il mio app.jscodice

var express = require('express');
var fs = require('fs');

var privateKey = fs.readFileSync('sslcert/server.key');
var certificate = fs.readFileSync('sslcert/server.crt');

var credentials = {key: privateKey, cert: certificate};


var app = express.createServer(credentials);

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

app.listen(8000);

Quando lo eseguo, sembra rispondere solo alle richieste HTTP.

Ho scritto node.jsun'app HTTPS semplice basata su vaniglia :

var   fs = require("fs"),
      http = require("https");

var privateKey = fs.readFileSync('sslcert/server.key').toString();
var certificate = fs.readFileSync('sslcert/server.crt').toString();

var credentials = {key: privateKey, cert: certificate};

var server = http.createServer(credentials,function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
});

server.listen(8000);

E quando si esegue questa applicazione, si fa rispondere a richieste HTTPS. Nota che non penso che toString () sul risultato fs sia importante, dato che ho usato combinazioni di entrambi e ancora no es bueno.


MODIFICA DA AGGIUNGERE:

Per i sistemi di produzione, probabilmente stai meglio usando Nginx o HAProxy per inoltrare richieste all'app del tuo nodojs. Puoi configurare nginx per gestire le richieste ssl e semplicemente parlare http al tuo nodo app.js.

MODIFICA DA AGGIUNGERE (06/04/2015)

Per i sistemi che utilizzano AWS, è meglio utilizzare i bilanciatori di carico elastici EC2 per gestire la terminazione SSL e consentire il traffico HTTP regolare ai server Web EC2. Per ulteriore sicurezza, imposta il tuo gruppo di sicurezza in modo tale che solo all'ELB sia consentito inviare traffico HTTP alle istanze EC2, impedendo al traffico HTTP esterno non crittografato di colpire i tuoi computer.



3
Ha risposto succintamente qui: stackoverflow.com/a/23894573/1882064
arcseldon

Per quanto riguarda l'ultimo commento su AWS: è necessario che un server non debba essere creato con il modulo https? I miei certificati vengono caricati in AWS tramite Jenkins e gestiti con ARN; Non ho percorsi di file da utilizzare (nelle opzioni https)
sqldoug

@sqldoug Non sono sicuro di aver capito la domanda. Gli ELB AWS possono essere configurati per accettare connessioni HTTPS e fungere da punto di terminazione SSL. Cioè, parlano ai server delle app tramite HTTP normale. Non esiste in genere un motivo per gestire i nodijs con SSL, poiché è solo un sovraccarico di elaborazione aggiuntivo che può essere gestito nello stack a livello di ELB oa livello di proxy HTTP.
Alan,

Grazie Alan; sì, da allora mi sono reso conto che Node non ha bisogno di gestire SSL quando AWS ELBs può essere così configurato.
sqldoug,

Risposte:


673

In express.js (dalla versione 3) dovresti usare quella sintassi:

var fs = require('fs');
var http = require('http');
var https = require('https');
var privateKey  = fs.readFileSync('sslcert/server.key', 'utf8');
var certificate = fs.readFileSync('sslcert/server.crt', 'utf8');

var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var app = express();

// your express configuration here

var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);

httpServer.listen(8080);
httpsServer.listen(8443);

In questo modo si fornisce middleware espresso al server http / https nativo

Se vuoi che la tua app funzioni su porte inferiori a 1024, dovrai usare il sudocomando (non raccomandato) o utilizzare un proxy inverso (ad esempio nginx, haproxy).


2
Tutto è scritto qui: github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x Funzione dell'applicazione
nome in codice

74
Si noti che sebbene 443 sia la porta predefinita per HTTPS, durante lo sviluppo probabilmente si desidera utilizzare qualcosa come 8443 perché la maggior parte dei sistemi non consente listener non root su porte con numero basso.
ebohlman,

1
Amico, funziona come per magia :) Accetta anche file .pem, come dovrebbe comunque
Marcelo Teixeira Ruggeri,

5
express 4 non funziona, funziona localhost:80ma nonhttps://localhost:443
Muhammad Umer,

13
se hai intenzione di utilizzare nginx per il proxy inverso, questo può gestire i certificati ssl per te invece del nodo
Gianfranco P.

48

Innanzitutto, è necessario creare i file selfsigned.key e selfsigned.crt . Vai a Creare un certificato SSL autofirmato oppure procedi come segue.

Vai al terminale ed esegui il seguente comando.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./selfsigned.key -out selfsigned.crt

  • Successivamente, inserisci le seguenti informazioni
  • Nome paese (codice di 2 lettere) [AU]: USA
  • Nome dello stato o della provincia (nome completo) [Some-State]: NY
  • Nome località (ad es. Città) []: NY
  • Nome dell'organizzazione (es. Società) [Internet Widgits Pty Ltd]: xyz (Your - Organization)
  • Nome unità organizzativa (ad es. Sezione) []: xyz (nome dell'unità)
  • Nome comune (ad es. FQDN del server o nome TUO) []: www.xyz.com (il tuo URL)
  • Indirizzo e-mail []: la tua e-mail

Dopo la creazione, aggiungi il file key & cert nel tuo codice e passa le opzioni al server.

const express = require('express');
const https = require('https');
const fs = require('fs');
const port = 3000;

var key = fs.readFileSync(__dirname + '/../certs/selfsigned.key');
var cert = fs.readFileSync(__dirname + '/../certs/selfsigned.crt');
var options = {
  key: key,
  cert: cert
};

app = express()
app.get('/', (req, res) => {
   res.send('Now using https..');
});

var server = https.createServer(options, app);

server.listen(port, () => {
  console.log("server starting on port : " + port)
});
  • Finalmente esegui la tua applicazione usando https .

Maggiori informazioni https://github.com/sagardere/set-up-SSL-in-nodejs


L'uso di sudo dovrebbe essere scoraggiato se non necessario. Ho appena completato questo processo senza usare sudo, ma sono stato eseguito l'accesso come amministratore sulla macchina.
jhickok,

27

Ho riscontrato un problema simile nel far funzionare SSL su una porta diversa dalla porta 443. Nel mio caso avevo un certificato bundle, un certificato e una chiave. Il certificato bundle è un file che contiene più certificati, il nodo richiede che questi certificati vengano suddivisi in elementi separati di un array.

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

    var options = {
      ca: [fs.readFileSync(PATH_TO_BUNDLE_CERT_1), fs.readFileSync(PATH_TO_BUNDLE_CERT_2)],
      cert: fs.readFileSync(PATH_TO_CERT),
      key: fs.readFileSync(PATH_TO_KEY)
    };

    app = express()

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

    var server = https.createServer(options, app);

    server.listen(8001, function(){
        console.log("server running at https://IP_ADDRESS:8001/")
    });

In app.js devi specificare https e creare il server di conseguenza. Inoltre, assicurati che la porta che stai tentando di utilizzare stia effettivamente consentendo il traffico in entrata.


ho una chiave e un certificato in bundle, non sono sicuro di quale certificato: fs.readFileSync (PATH_TO_CERT), sarebbe e come "rompere" il certificato in bundle, se ci chiedi ci sono più di 20 chiavi in ​​certificato se me lo chiedi :)
Muhammad Umar,

@MuhammadUmar non devi rompere il bundle o persino specificarlo se non ne hai uno, avrai un cert bundle se applicabile, e cert (chiave pubblica) e chiave (chiave privata)
Hayden Thring

@eomoto grazie amico! questo è il migliore, hai completamente inchiodato l'esempio di cui avevo bisogno
Hayden Thring

11

Compresi punti:

  1. Configurazione SSL
    1. In config / local.js
    2. In config / env / production.js

Gestione HTTP e WS

  1. L'app deve essere eseguita su HTTP in fase di sviluppo in modo da poter eseguire facilmente il debug della nostra app.
  2. L'app deve essere eseguita su HTTPS in produzione per motivi di sicurezza.
  3. La richiesta HTTP per la produzione di app deve sempre reindirizzare a https.

Configurazione SSL

In Sailsjs ci sono due modi per configurare tutte le cose, in primo luogo è configurare nella cartella config con ognuna ha i propri file separati (come la connessione al database per quanto riguarda le impostazioni si trova in connections.js). E in secondo luogo è configurato sulla struttura dei file di base dell'ambiente, ogni file di ambiente presenta nella config/envcartella e ogni file contiene le impostazioni per env particolare.

Le vele prima guardano nella cartella config / env e poi attendono config / * .js

Ora consente l'installazione di ssl config/local.js.

var local = {
   port: process.env.PORT || 1337,
   environment: process.env.NODE_ENV || 'development'
};

if (process.env.NODE_ENV == 'production') {
    local.ssl = {
        secureProtocol: 'SSLv23_method',
        secureOptions: require('constants').SSL_OP_NO_SSLv3,
        ca: require('fs').readFileSync(__dirname + '/path/to/ca.crt','ascii'),
        key: require('fs').readFileSync(__dirname + '/path/to/jsbot.key','ascii'),
        cert: require('fs').readFileSync(__dirname + '/path/to/jsbot.crt','ascii')
    };
    local.port = 443; // This port should be different than your default port
}

module.exports = local;

In alternativa puoi aggiungerlo anche in config / env / production.js . (Questo frammento mostra anche come gestire più certificazioni CARoot)

O in production.js

module.exports = {
    port: 443,
    ssl: {
        secureProtocol: 'SSLv23_method',
        secureOptions: require('constants').SSL_OP_NO_SSLv3,
        ca: [
            require('fs').readFileSync(__dirname + '/path/to/AddTrustExternalCARoot.crt', 'ascii'),
            require('fs').readFileSync(__dirname + '/path/to/COMODORSAAddTrustCA.crt', 'ascii'),
            require('fs').readFileSync(__dirname + '/path/to/COMODORSADomainValidationSecureServerCA.crt', 'ascii')
        ],
        key: require('fs').readFileSync(__dirname + '/path/to/jsbot.key', 'ascii'),
        cert: require('fs').readFileSync(__dirname + '/path/to/jsbot.crt', 'ascii')
    }
};

http / https & ws / wss reindirizzamento

Qui ws è Web Socket e wss rappresentano Secure Web Socket, poiché impostiamo ssl allora ora http e ws entrambe le richieste diventano sicure e si trasformano rispettivamente in https e wss.

Ci sono molte fonti dalla nostra app che riceveranno richieste come qualsiasi post sul blog, post sui social media ma il nostro server funziona solo su https, quindi quando qualsiasi richiesta proviene da http viene visualizzato l'errore "Impossibile raggiungere questo sito" nel browser client. E perdiamo il traffico del nostro sito web. Quindi dobbiamo reindirizzare la richiesta http su https, le stesse regole consentono il websocket altrimenti il ​​socket fallirà.

Quindi dobbiamo eseguire lo stesso server sulla porta 80 (http) e deviare tutte le richieste sulla porta 443 (https). Vele prima compilare il file config / bootstrap.js prima di sollevare il server. Qui possiamo avviare il nostro server espresso sulla porta 80.

In config / bootstrap.js (Crea server http e reindirizza tutte le richieste su https)

module.exports.bootstrap = function(cb) {
    var express = require("express"),
        app = express();

    app.get('*', function(req, res) {  
        if (req.isSocket) 
            return res.redirect('wss://' + req.headers.host + req.url)  

        return res.redirect('https://' + req.headers.host + req.url)  
    }).listen(80);
    cb();
};

Ora puoi visitare http://www.yourdomain.com , reindirizzerà a https://www.tuodominio.com


8

Usa greenlock-express: SSL gratuito, HTTPS automatizzato

Greenlock gestisce l'emissione e il rinnovo del certificato (tramite Let's Encrypt) e il reindirizzamento https http =>, pronto all'uso .

express-app.js:

var express = require('express');
var app = express();

app.use('/', function (req, res) {
  res.send({ msg: "Hello, Encrypted World!" })
});

// DO NOT DO app.listen()
// Instead export your app:
module.exports = app;

server.js:

require('greenlock-express').create({
  // Let's Encrypt v2 is ACME draft 11
  version: 'draft-11'
, server: 'https://acme-v02.api.letsencrypt.org/directory'

  // You MUST change these to valid email and domains
, email: 'john.doe@example.com'
, approveDomains: [ 'example.com', 'www.example.com' ]
, agreeTos: true
, configDir: "/path/to/project/acme/"

, app: require('./express-app.j')

, communityMember: true // Get notified of important updates
, telemetry: true       // Contribute telemetry data to the project
}).listen(80, 443);

screencast

Guarda la dimostrazione di avvio rapido: https://youtu.be/e8vaR4CEZ5s

Per Localhost

Basta rispondere a questa domanda in anticipo perché è una domanda di follow-up comune:

Non puoi avere certificati SSL su localhost. Tuttavia, puoi usare qualcosa come Telebit che ti consentirà di eseguire app locali come vere e proprie.

Puoi anche usare domini privati ​​con Greenlock tramite sfide DNS-01, che è menzionato nel README insieme a vari plugin che lo supportano.

Porte non standard (ovvero no 80/443)

Leggi la nota sopra su localhost: non puoi nemmeno usare porte non standard con Let's Encrypt.

Tuttavia, puoi esporre le tue porte non standard interne come porte standard esterne tramite port forwarding, sni-route o utilizzare qualcosa come Telebit che esegue il routing SNI e il port forwarding / relay per te.

Puoi anche utilizzare le sfide DNS-01, nel qual caso non dovrai esporre affatto le porte e puoi anche proteggere domini su reti private in questo modo.


"Non puoi avere certificati SSL su localhost." - Ho SSL che funziona sulla mia app React su localhost. Sono venuto qui alla ricerca di come farlo funzionare in Express. React è il mio frontend ed Express è il mio backend. Ho bisogno che funzioni per Stripe, dal momento che il mio post su Stripe deve essere in SSL. Dovrebbe essere ovvio, ma in localhost sto testando e sul server sarà la produzione.
Taersious

Correzione: "Non è possibile avere certificati SSL validi su localhost".
CoolAJ86,

6

Funziona così per me. Il reindirizzamento utilizzato reindirizzerà anche tutti i normali http.

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
var request = require('request');
//For https
const https = require('https');
var fs = require('fs');
var options = {
  key: fs.readFileSync('certificates/private.key'),
  cert: fs.readFileSync('certificates/certificate.crt'),
  ca: fs.readFileSync('certificates/ca_bundle.crt')
};

// API file for interacting with MongoDB
const api = require('./server/routes/api');

// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Angular DIST output folder
app.use(express.static(path.join(__dirname, 'dist')));

// API location
app.use('/api', api);

// Send all other requests to the Angular app
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.use(function(req,resp,next){
  if (req.headers['x-forwarded-proto'] == 'http') {
      return resp.redirect(301, 'https://' + req.headers.host + '/');
  } else {
      return next();
  }
});


http.createServer(app).listen(80)
https.createServer(options, app).listen(443);

0

Questo è il mio codice di lavoro per Express 4.0 .

express 4.0 è molto diverso da 3.0 e altri.

4.0 hai il file / bin / www, che aggiungerai qui https.

"npm start" è il modo standard in cui si avvia il server Express 4.0.

La funzione readFileSync () dovrebbe usare __dirname per ottenere la directory corrente

while require () use ./ consultare la directory corrente.

Per prima cosa metti il ​​file private.key e public.cert nella cartella / bin, è la stessa cartella del file WWW .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.