Włączanie HTTPS na express.js

408

Próbuję zmusić HTTPS do pracy na express.js dla węzła i nie mogę tego rozgryźć.

To jest mój app.jskod.

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

Po uruchomieniu wydaje się odpowiadać tylko na żądania HTTP.

Napisałem prostą node.jsaplikację HTTPS opartą na wanilii :

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

I kiedy uruchomić tę aplikację, to nie reagować na żądania HTTPS. Zauważ, że nie sądzę, że toString () na wyniku fs ma znaczenie, ponieważ użyłem kombinacji obu i wciąż nie ma es bueno.


EDYTUJ, ABY DODAĆ:

W przypadku systemów produkcyjnych prawdopodobnie lepiej jest używać Nginx lub HAProxy do przesyłania żądań proxy do aplikacji nodejs. Możesz skonfigurować nginx do obsługi żądań ssl i po prostu mówić http do twojego app.js.

EDYTUJ, ABY DODAĆ (4/6/2015)

W przypadku systemów korzystających z AWS lepiej jest używać EC2 Elastic Load Balancers do obsługi terminacji SSL i zezwalać na regularny ruch HTTP do serwerów sieciowych EC2. Aby zwiększyć bezpieczeństwo, skonfiguruj swoją grupę zabezpieczeń tak, aby tylko ELB mógł wysyłać ruch HTTP do instancji EC2, co zapobiegnie uderzeniu zewnętrznego nieszyfrowanego ruchu HTTP w twoje maszyny.


Alan
źródło
3
Odpowiedzi zwięźle tutaj: stackoverflow.com/a/23894573/1882064
arcseldon
W odniesieniu do ostatniego komentarza na temat AWS: czy serwer nie musi być tworzony za pomocą modułu https? Moje certyfikaty są przesyłane do AWS przez Jenkins i obsługiwane przez ARN; Nie mam ścieżek plików do użycia (w opcjach https)
sqldoug
@sqldoug Nie jestem pewien, czy rozumiem pytanie. ELS AWS można skonfigurować tak, aby akceptowały połączenia HTTPS i działały jako punkt końcowy SSL. Oznacza to, że rozmawiają z serwerami aplikacji za pośrednictwem zwykłego protokołu HTTP. Zwykle nie ma powodu, aby nodejs zajmował się SSL, ponieważ jest to tylko dodatkowy narzut przetwarzania, który można obsłużyć stos na poziomie ELB lub na poziomie proxy HTTP.
Alan
Dzięki Alan; tak, od tamtej pory zdałem sobie sprawę, że Węzeł nie musi zajmować się SSL, kiedy można tak skonfigurować ELB AWS.
sqldoug

Odpowiedzi:

672

W express.js (od wersji 3) powinieneś użyć tej składni:

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

W ten sposób dostarczasz ekspresowe oprogramowanie pośrednie do macierzystego serwera http / https

Jeśli chcesz, aby Twoja aplikacja działała na portach poniżej 1024, musisz użyć sudopolecenia (niezalecane) lub odwrotnego proxy (np. Nginx, haproxy).

kryptonim-
źródło
2
Wszystko jest napisane tutaj: github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x Funkcja aplikacji
kryptonim
74
Zauważ, że chociaż 443 jest domyślnym portem dla HTTPS, podczas programowania prawdopodobnie będziesz chciał użyć czegoś takiego jak 8443, ponieważ większość systemów nie zezwala na nasłuchiwanie użytkownika innego niż root na portach o niskim numerze.
ebohlman
1
Człowieku, działa jak magia :) Akceptuje również pliki .pem, tak jak powinno
Marcelo Teixeira Ruggeri
5
express 4 nie działa, działa, localhost:80ale nie działahttps://localhost:443
Muhammad Umer
13
jeśli zamierzasz użyć nginx do odwrotnego proxy, który może obsłużyć certyfikaty ssl dla ciebie zamiast węzła
Gianfranco P.
48

Najpierw musisz utworzyć pliki selfsigned.key i selfsigned.crt . Przejdź do Utwórz samopodpisany certyfikat SSL lub wykonaj następujące czynności.

Przejdź do terminala i uruchom następującą komendę.

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

  • Następnie umieść następujące informacje
  • Nazwa kraju (dwuliterowy kod) [AU]: US
  • Nazwa stanu lub prowincji (pełna nazwa) [Some-State]: NY
  • Nazwa miejscowości (np. Miasto) []: NY
  • Nazwa organizacji (np. Firma) [Internet Widgits Pty Ltd]: xyz (Your - Organization)
  • Nazwa jednostki organizacyjnej (np. Sekcja) []: xyz (Twoja nazwa jednostki)
  • Nazwa zwyczajowa (np. Nazwa FQDN serwera lub TWOJA nazwa) []: www.xyz.com (Twój adres URL)
  • Adres e-mail []: Twój adres e-mail

Po utworzeniu dodaje plik klucza i certyfikatu do kodu i przekazuje opcje do serwera.

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)
});
  • Na koniec uruchom aplikację za pomocą https .

Więcej informacji https://github.com/sagardere/set-up-SSL-in-nodejs

Dere Sagar
źródło
Używanie sudo powinno być odradzane, chyba że jest to konieczne. Właśnie przeszedłem ten proces bez użycia sudo, ale byłem zalogowany jako administrator na komputerze.
jhickok
27

Wystąpił podobny problem z uruchomieniem protokołu SSL na porcie innym niż port 443. W moim przypadku miałem certyfikat pakietu, a także certyfikat i klucz. Certyfikat pakietu to plik, który zawiera wiele certyfikatów, węzeł wymaga rozbicia tych certyfikatów na osobne elementy tablicy.

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

W app.js musisz podać https i odpowiednio utworzyć serwer. Upewnij się także, że port, którego próbujesz użyć, zezwala na ruch przychodzący.

eomoto
źródło
mam klucz i dołączony certyfikat, nie jestem pewien, jaki byłby certyfikat: fs.readFileSync (PATH_TO_CERT) i jak „złamać” dołączony certyfikat, w certyfikacie jest ponad 20 kluczy, jeśli mnie zapytasz :)
Muhammad Umar
@MuhammadUmar nie musisz łamać pakietu, a nawet określić, jeśli go nie masz, będziesz mieć pakiet certyfikatu, jeśli dotyczy, oraz cert (klucz publiczny) i klucz (klucz prywatny)
Hayden Thring
@eomoto dzięki bud! to jest najlepsze, całkowicie przybiłeś przykład, którego potrzebowałem
Hayden Thring
11

Łącznie z punktami:

  1. Konfiguracja SSL
    1. W config / local.js
    2. W config / env / production.js

Obsługa HTTP i WS

  1. Aplikacja musi działać na HTTP w fazie rozwoju, abyśmy mogli łatwo debugować naszą aplikację.
  2. Ze względów bezpieczeństwa aplikacja musi być uruchomiona na HTTPS w produkcji.
  3. Żądanie HTTP produkcji aplikacji powinno zawsze przekierowywać na https.

Konfiguracja SSL

W Sailsjs istnieją dwa sposoby skonfigurowania wszystkich rzeczy, po pierwsze, konfiguracja w folderze config, z którym każdy ma swoje osobne pliki (np. Połączenie z bazą danych dotyczące ustawień leży w obrębie połączeń.js). Drugi to konfiguracja na podstawie podstawowej struktury plików, każdy plik środowiskowy znajduje się w config/envfolderze, a każdy plik zawiera ustawienia dla konkretnej środowiska.

Żagle najpierw szukają w folderze config / env, a następnie czekają na config / * .js

Teraz pozwala na konfigurację 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;

Alternatywnie możesz dodać to również w config / env / production.js . (Ten fragment pokazuje również, jak obsługiwać wiele certyfikatów CARoot)

Lub w 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')
    }
};

Przekierowanie http / https & ws / wss

Tutaj WS jest Web Socket, a wss reprezentuje Secure Web Socket, ponieważ skonfigurowaliśmy ssl, teraz HTTP i WS oba żądania stają się bezpieczne i przekształcają się odpowiednio w https i wss.

Istnieje wiele źródeł z naszej aplikacji, które otrzymają żądanie, jak każdy post na blogu, post w mediach społecznościowych, ale nasz serwer działa tylko na https, więc gdy każde żądanie pochodzi z http, pojawia się błąd „Nie można dotrzeć do tej witryny” w przeglądarce klienta. I tracimy ruch w naszej witrynie. Musimy więc przekierować żądanie HTTP do https, te same reguły zezwalają na websocket, w przeciwnym razie gniazdo zawiedzie.

Musimy więc uruchomić ten sam serwer na porcie 80 (http) i przekierować wszystkie żądania na port 443 (https). Najpierw kompiluje plik config / bootstrap.js przed podniesieniem serwera. Tutaj możemy uruchomić nasz serwer ekspresowy na porcie 80.

W config / bootstrap.js (Utwórz serwer http i przekieruj wszystkie żądania do 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();
};

Teraz możesz odwiedzić witrynę http://www.twojadomena.com , nastąpi przekierowanie do https://www.twojadomena.com

Nishchit Dhanani
źródło
8

Użyj greenlock-express: bezpłatny SSL, zautomatyzowany HTTPS

Greenlock obsługuje wydawanie i odnawianie certyfikatów (przez Let's Encrypt) i przekierowanie https, po wyjęciu z pudełka.

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

Obejrzyj prezentację QuickStart: https://youtu.be/e8vaR4CEZ5s

Dla Localhost

Odpowiadając na to z wyprzedzeniem, ponieważ jest to częste pytanie uzupełniające:

Nie możesz mieć certyfikatów SSL na localhost. Możesz jednak użyć czegoś takiego jak Telebit który pozwoli ci uruchamiać lokalne aplikacje jako prawdziwe.

Możesz także korzystać z domen prywatnych z Greenlockiem za pośrednictwem wyzwań DNS-01, które są wymienione w README wraz z różnymi wtyczkami, które go obsługują.

Porty niestandardowe (tj. Nr 80/443)

Przeczytaj powyższą notatkę o localhost - nie możesz używać niestandardowych portów w Let's Encrypt.

Możesz jednak ujawnić swoje niestandardowe porty wewnętrzne jako zewnętrzne porty standardowe za pomocą przekierowania portów, sni-route lub użyć czegoś takiego jak Telebit, który wykonuje routing SNI oraz przekierowywanie / przekazywanie portów.

Możesz także użyć wyzwań DNS-01, w którym to przypadku nie będziesz musiał w ogóle ujawniać portów, a także w ten sposób możesz zabezpieczyć domeny w sieciach prywatnych.

CoolAJ86
źródło
„Nie możesz mieć certyfikatów SSL na localhost.” - Mam SSL działający w mojej aplikacji React na localhost. Przybyłem tutaj, aby dowiedzieć się, jak to zrobić w Express. React to mój frontend, a Express to mój backend. Potrzebuję go do pracy dla Stripe, ponieważ mój post do Stripe musi być w SSL. Powinno być oczywiste, ale w localhost testuję, a na serwerze będzie to produkcja.
Taersious
Korekta: „Nie możesz mieć ważnego certyfikatów SSL na localhost”.
CoolAJ86,
6

Tak to dla mnie działa. Zastosowane przekierowanie przekieruje również wszystkie normalne 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);
shantanu Chandra
źródło
0

To jest mój działający kod dla express 4.0 .

express 4.0 różni się bardzo od 3.0 i innych.

4.0 masz plik / bin / www, który tutaj dodasz https.

„npm start” to standardowy sposób uruchamiania serwera Express 4.0.

Funkcja readFileSync () powinna używać __nazwa_katalogu pobrać bieżący katalog

while while () użyj ./ odnosi się do bieżącego katalogu.

Najpierw umieść plik private.key i public.cert w folderze / bin, jest to ten sam folder, co plik WWW .

hoogw
źródło