Activer HTTPS sur express.js

408

J'essaie de faire fonctionner HTTPS sur express.js pour le nœud, et je ne peux pas le comprendre.

Ceci est mon app.jscode.

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

Lorsque je l'exécute, il semble ne répondre qu'aux requêtes HTTP.

J'ai écrit une node.jsapplication HTTPS simple à base de vanille :

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

Et quand je lance cette application, il ne répondre aux demandes HTTPS. Notez que je ne pense pas que le toString () sur le résultat fs importe, car j'ai utilisé des combinaisons des deux et toujours pas d'es bueno.


MODIFIER POUR AJOUTER:

Pour les systèmes de production, vous feriez probablement mieux d'utiliser Nginx ou HAProxy pour proxy des requêtes vers votre application nodejs. Vous pouvez configurer nginx pour gérer les requêtes SSL et parler simplement http à votre nœud app.js.

MODIFIER POUR AJOUTER (4/6/2015)

Pour les systèmes utilisant AWS, il vaut mieux utiliser les équilibreurs de charge élastiques EC2 pour gérer la terminaison SSL et autoriser le trafic HTTP régulier vers vos serveurs Web EC2. Pour plus de sécurité, configurez votre groupe de sécurité de sorte que seul l'ELB soit autorisé à envoyer du trafic HTTP vers les instances EC2, ce qui empêchera le trafic HTTP non chiffré externe de toucher vos machines.


Alan
la source
3
Répondu succinctement ici: stackoverflow.com/a/23894573/1882064
arcseldon
Concernant le dernier commentaire sur AWS: est-ce qu'un serveur n'a pas besoin d'être créé avec le module https? Mes certificats sont téléchargés dans AWS via Jenkins et traités avec ARN; Je n'ai aucun chemin de fichier à utiliser (dans les options https)
sqldoug
@sqldoug Je ne suis pas sûr de comprendre la question. Les ELB AWS peuvent être configurés pour accepter les connexions HTTPS et agir comme point de terminaison SSL. Autrement dit, ils parlent à vos serveurs d'applications via HTTP standard. Il n'y a généralement pas de raison pour que nodejs s'occupe de SSL, car c'est juste une surcharge de traitement supplémentaire qui peut être gérée dans la pile au niveau ELB ou au niveau du proxy HTTP.
Alan
Merci Alan; oui, j'ai depuis réalisé que Node n'a pas besoin de gérer SSL lorsque les ELB AWS peuvent être ainsi configurés.
sqldoug

Réponses:

673

Dans express.js (depuis la version 3), vous devez utiliser cette syntaxe:

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

De cette façon, vous fournissez un middleware express au serveur http / https natif

Si vous souhaitez que votre application s'exécute sur des ports inférieurs à 1024, vous devrez utiliser la sudocommande (non recommandée) ou utiliser un proxy inverse (par exemple nginx, haproxy).

nom de code-
la source
2
Tout est écrit ici: github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x Paragraphe Fonction d'application
nom de code
74
Notez que bien que 443 soit le port par défaut pour HTTPS, pendant le développement, vous voudrez probablement utiliser quelque chose comme 8443 car la plupart des systèmes n'autorisent pas les écouteurs non root sur les ports à faible numéro.
ebohlman
1
Mec, ça marche comme par magie :) Il accepte aussi les fichiers .pem, comme il se doit
Marcelo Teixeira Ruggeri
5
express 4 ça ne marche pas, ça marche localhost:80mais pashttps://localhost:443
Muhammad Umer
13
si vous allez utiliser nginx pour le proxy inverse, qui peut gérer les certificats SSL pour vous au lieu du nœud
Gianfranco P.
48

Tout d'abord, vous devez créer des fichiers selfsigned.key et selfsigned.crt . Accédez à Créer un certificat SSL auto-signé ou procédez comme suit.

Accédez au terminal et exécutez la commande suivante.

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

  • Après cela, mettez les informations suivantes
  • Nom du pays (code à 2 lettres) [AU]: US
  • Nom de l'État ou de la province (nom complet) [Quel État]: NY
  • Nom de localité (par exemple, ville) []: NY
  • Nom de l'organisation (par exemple, société) [Internet Widgits Pty Ltd]: xyz (Votre - Organisation)
  • Nom de l'unité organisationnelle (par exemple, section) []: xyz (nom de votre unité)
  • Nom commun (par exemple nom de domaine complet du serveur ou VOTRE nom) []: www.xyz.com (votre URL)
  • Adresse e-mail []: votre adresse e-mail

Après la création, ajoute le fichier key & cert dans votre code et transmettez les options au serveur.

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)
});
  • Enfin, exécutez votre application en utilisant https .

Plus d'informations https://github.com/sagardere/set-up-SSL-in-nodejs

Dere Sagar
la source
L'utilisation de sudo doit être déconseillée, sauf si cela est nécessaire. Je viens de passer par ce processus sans utiliser sudo, mais j'étais connecté en tant qu'administrateur sur la machine.
jhickok
27

J'ai rencontré un problème similaire avec l'obtention de SSL pour travailler sur un port autre que le port 443. Dans mon cas, j'avais un certificat de bundle ainsi qu'un certificat et une clé. Le certificat de bundle est un fichier qui contient plusieurs certificats, le nœud nécessite que vous divisiez ces certificats en éléments distincts d'un tableau.

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

Dans app.js, vous devez spécifier https et créer le serveur en conséquence. Assurez-vous également que le port que vous essayez d'utiliser autorise réellement le trafic entrant.

eomoto
la source
J'ai une clé et un certificat groupé, je ne sais pas quel certificat: fs.readFileSync (PATH_TO_CERT), serait et comment "casser" le certificat groupé, il y a plus de 20 clés dans le certificat si vous me demandez :)
Muhammad Umar
@MuhammadUmar vous n'avez pas besoin de casser le bundle ou même de le spécifier si vous n'en avez pas, vous aurez un certificat de bundle le cas échéant, et cert (clé publique) et clé (clé privée)
Hayden Thring
@eomoto merci bud! c'est le meilleur, vous avez totalement cloué l'exemple dont j'avais besoin
Hayden Thring
11

Y compris les points:

  1. Configuration SSL
    1. Dans config / local.js
    2. Dans config / env / production.js

Gestion HTTP et WS

  1. L'application doit fonctionner sur HTTP en cours de développement afin que nous puissions facilement déboguer notre application.
  2. L'application doit fonctionner sur HTTPS en production pour des raisons de sécurité.
  3. La demande HTTP de production d'application doit toujours être redirigée vers https.

Configuration SSL

Dans Sailsjs, il y a deux façons de configurer toutes les choses, la première consiste à configurer dans le dossier config avec chacun a ses fichiers séparés (comme la connexion à la base de données concernant les paramètres se trouve dans connections.js). Et le second est de configurer la structure de fichier de base de l'environnement, chaque fichier d'environnement se présente dansconfig/env dossier et chaque fichier contient des paramètres pour un environnement particulier.

Sails regarde d'abord dans le dossier config / env puis attend avec impatience config / * .js

Permet maintenant de configurer 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;

Alternativement, vous pouvez également l'ajouter dans config / env / production.js . (Cet extrait montre également comment gérer plusieurs certificats CARoot)

Ou dans 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')
    }
};

Redirection http / https & ws / wss

Ici, ws est Web Socket et wss représente Secure Web Socket, car nous configurons ssl puis maintenant http et ws les deux demandes deviennent sécurisées et se transforment respectivement en https et wss.

Il existe de nombreuses sources de notre application qui recevront une demande comme tout article de blog, publication sur les réseaux sociaux, mais notre serveur ne fonctionne que sur https, donc lorsque toute demande provient de http, il affiche l'erreur "Ce site est inaccessible" dans le navigateur du client. Et nous perdons le trafic de notre site Web. Nous devons donc rediriger la requête http vers https, les mêmes règles autorisent le websocket sinon le socket échouera.

Nous devons donc exécuter le même serveur sur le port 80 (http) et détourner toutes les demandes vers le port 443 (https). Sails compile d'abord le fichier config / bootstrap.js avant de lever le serveur. Ici, nous pouvons démarrer notre serveur express sur le port 80.

Dans config / bootstrap.js (créer un serveur http et rediriger toutes les demandes vers 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();
};

Vous pouvez maintenant visiter http://www.votredomaine.com , il sera redirigé vers https://www.votredomaine.com

Nishchit Dhanani
la source
8

Utilisez greenlock-express: SSL gratuit, HTTPS automatisé

Greenlock gère l'émission et le renouvellement des certificats (via Let's Encrypt) et la redirection http => https, .

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: '[email protected]'
, 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

Regardez la démonstration QuickStart: https://youtu.be/e8vaR4CEZ5s

Pour Localhost

Répondre à cette question à l'avance, car c'est une question de suivi courante:

Vous ne pouvez pas avoir de certificats SSL sur localhost. Cependant, vous pouvez utiliser quelque chose comme Telebit qui vous permettra d'exécuter des applications locales comme de vraies.

Vous pouvez également utiliser des domaines privés avec Greenlock via des défis DNS-01, qui sont mentionnés dans le README avec divers plugins qui le prennent en charge.

Ports non standard (c'est-à-dire non 80/443)

Lisez la note ci-dessus à propos de localhost - vous ne pouvez pas non plus utiliser de ports non standard avec Let's Encrypt.

Cependant, vous pouvez exposer vos ports internes non standard en tant que ports standard externes via le port forward, sni-route ou utiliser quelque chose comme Telebit qui fait le routage SNI et le port forwarding / relaying pour vous.

Vous pouvez également utiliser des défis DNS-01, auquel cas vous n'aurez pas besoin d'exposer les ports du tout et vous pouvez également sécuriser des domaines sur des réseaux privés de cette façon.

CoolAJ86
la source
"Vous ne pouvez pas avoir de certificats SSL sur localhost." - J'ai SSL qui travaille sur mon application React sur localhost. Je suis venu ici en cherchant comment le faire fonctionner dans Express. React est mon frontend et Express est mon backend. J'en ai besoin pour travailler pour Stripe, car mon message sur Stripe doit être en SSL. Cela devrait être évident, mais dans localhost, je teste, et sur le serveur, ce sera la production.
Taersious
Correction: "Vous ne pouvez pas avoir de certificats SSL valides sur localhost".
CoolAJ86
6

C'est comme ça que ça marche pour moi. La redirection utilisée redirigera également tous les http normaux.

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);
shantanu Chandra
la source
0

Ceci est mon code de travail pour express 4.0 .

express 4.0 est très différent de 3.0 et d'autres.

4.0 vous avez le fichier / bin / www, que vous allez ajouter https ici.

"npm start" est la manière standard de démarrer le serveur express 4.0.

La fonction readFileSync () doit utiliser __dirname obtenir le répertoire courant

tandis que require () utilise ./ réfère au répertoire courant.

Vous mettez d'abord le fichier private.key et public.cert dans le dossier / bin, c'est le même dossier que le fichier WWW .

hoogw
la source