Включение HTTPS в express.js

408

Я пытаюсь заставить HTTPS работать над express.js для узла, и я не могу понять это.

Это мой app.jsкод

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

Когда я запускаю его, кажется, что он отвечает только на HTTP-запросы.

Я написал простое node.jsприложение HTTPS на основе ванили :

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

И когда я запускаю это приложение, это делает реагировать на HTTPS запросы. Обратите внимание, что я не думаю, что toString () для результата fs имеет значение, так как я использовал комбинации обоих и до сих пор нет es bueno.


РЕДАКТИРОВАТЬ ДОБАВИТЬ:

Для производственных систем вам, вероятно, лучше использовать Nginx или HAProxy для прокси-запросов к вашему приложению nodejs. Вы можете настроить nginx для обработки запросов ssl и просто говорить http для вашего узла app.js.

РЕДАКТИРОВАТЬ ДОБАВИТЬ (06.04.2015)

Для систем, использующих AWS, лучше использовать EC2 Elastic Load Balancers для обработки завершения SSL и разрешать регулярный HTTP-трафик на ваши веб-серверы EC2. Для обеспечения дополнительной безопасности настройте свою группу безопасности таким образом, чтобы только ELB мог отправлять HTTP-трафик экземплярам EC2, что предотвратит попадание внешнего незашифрованного HTTP-трафика на ваши компьютеры.


Алан
источник
3
Кратко ответили
Что касается последнего комментария по AWS: не нужно ли создавать сервер с помощью модуля https? Мои сертификаты загружаются в AWS через Jenkins и обрабатываются с помощью ARN; У меня нет путей к файлам (в настройках https)
sqldoug
@sqldoug Я не уверен, что понимаю вопрос. AWS ELB могут быть настроены на прием HTTPS-соединений и выступать в качестве точки завершения SSL. То есть они общаются с вашими серверами приложений через обычный HTTP. Обычно нет причин для того, чтобы nodejs работал с SSL, потому что это просто дополнительные накладные расходы на обработку, которые можно обрабатывать в стеке либо на уровне ELB, либо на уровне HTTP-прокси.
Алан
Спасибо Алан; да, с тех пор я понял, что Node не нужно иметь дело с SSL, когда AWS ELB могут быть настроены таким образом.
sqldoug

Ответы:

673

В express.js (начиная с версии 3) вы должны использовать этот синтаксис:

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

Таким образом, вы предоставляете промежуточное программное обеспечение Express для собственного сервера http / https

Если вы хотите, чтобы ваше приложение работало на портах ниже 1024, вам нужно будет использовать sudoкоманду (не рекомендуется) или использовать обратный прокси-сервер (например, nginx, haproxy).

кодовое имя-
источник
2
Все написано здесь: github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x Абзац Функция приложения
кодовое имя
74
Обратите внимание, что хотя порт 443 является портом по умолчанию для HTTPS, во время разработки вы, вероятно, захотите использовать что-то вроде 8443, потому что большинство систем не допускают прослушиватели без полномочий root на портах с низким номером.
Ebohlman
1
Чувак, он работает как по волшебству :) Он также принимает файлы .pem, как и должно быть в любом случае
Marcelo Teixeira Ruggeri
5
Экспресс 4 это не работает, это работает, localhost:80но не работаетhttps://localhost:443
Мухаммед Умер
13
если вы собираетесь использовать nginx для обратного прокси-сервера, он может обрабатывать ssl-сертификаты вместо вас
Gianfranco P.
48

Во-первых, вам нужно создать файлы selfsigned.key и selfsigned.crt . Перейдите к созданию самоподписанного сертификата SSL или выполните следующие действия.

Подойдите к терминалу и выполните следующую команду.

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

  • После этого поставьте следующую информацию
  • Название страны (двухбуквенный код) [AU]: США
  • Название штата или провинции (полное название) [Some-State]: NY
  • Название населенного пункта (например, город) []: NY
  • Название организации (например, компания) [Internet Widgits Pty Ltd]: xyz (Ваша - Организация)
  • Название подразделения организации (например, раздел) []: xyz (Название подразделения)
  • Общее имя (например, полное доменное имя сервера или ваше имя) []: www.xyz.com (ваш URL)
  • Адрес электронной почты []: Ваш адрес электронной почты

После создания добавьте файл ключа и сертификата в ваш код и передайте параметры на сервер.

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)
});
  • Наконец, запустите ваше приложение, используя https .

Дополнительная информация https://github.com/sagardere/set-up-SSL-in-nodejs

Дере Сагар
источник
Использование sudo не рекомендуется, если в этом нет необходимости. Я только что прошел этот процесс без использования sudo, но я вошел как администратор на машине.
Джикок
27

Я столкнулся с аналогичной проблемой при получении SSL для работы на порте, отличном от порта 443. В моем случае у меня был пакетный сертификат, а также сертификат и ключ. Сертификат комплекта представляет собой файл, который содержит несколько сертификатов, узел требует, чтобы эти сертификаты были разбиты на отдельные элементы массива.

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

В app.js вам нужно указать https и соответственно создать сервер. Также убедитесь, что порт, который вы пытаетесь использовать, на самом деле разрешает входящий трафик.

eomoto
источник
у меня есть ключ и связанный сертификат, я не уверен, что будет сертификат: fs.readFileSync (PATH_TO_CERT), и как «сломать» связанный сертификат, если вы спросите меня, в сертификате есть 20+ ключей,
Мухаммед Умар
@MuhammadUmar вам не нужно ломать пакет или даже указывать его, если у вас его нет, у вас будет сертификат, если это применимо, и сертификат (открытый ключ) и ключ (закрытый ключ)
Hayden
@ eomoto спасибо, приятель! это лучшее, ты полностью прибил пример, который мне был нужен
Хайден Тринг
11

Включая очки:

  1. Настройка SSL
    1. В config / local.js
    2. В config / env / production.js

Обработка HTTP и WS

  1. При разработке приложение должно работать по HTTP, чтобы мы могли легко отлаживать наше приложение.
  2. Приложение должно работать на HTTPS на производстве в целях безопасности.
  3. HTTP-запрос приложения должен всегда перенаправляться на https.

Конфигурация SSL

В Sailsjs есть два способа настроить все вещи, во-первых, это настроить в папке конфигурации, у каждого из которых есть свои отдельные файлы (например, соединение с базой данных относительно настроек находится в файле connections.js). И, во-вторых, конфигурация на основе файловой структуры среды, каждый файл среды представлен в config/envпапке, и каждый файл содержит настройки для конкретной среды.

Парус сначала заглядывает в папку config / env, а затем ожидает config / * .js

Теперь давайте настроим 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;

В качестве альтернативы вы также можете добавить это в config / env / production.js . (Этот фрагмент также показывает, как работать с несколькими сертификатами CARoot)

Или в 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

Здесь ws - это Web Socket, а wss - это Secure Web Socket, так как мы настроили ssl, теперь http и ws оба запроса становятся безопасными и преобразуются в https и wss соответственно.

Многие источники из нашего приложения будут получать запросы, как и любые сообщения в блоге, публикации в социальных сетях, но наш сервер работает только по протоколу https, поэтому при поступлении любого запроса с http он выдает ошибку «Этот сайт недоступен» в клиентском браузере. И мы теряем трафик нашего сайта. Поэтому мы должны перенаправить http-запрос на https, те же правила разрешают использование websocket, иначе сокет не будет работать.

Поэтому нам нужно запустить один и тот же сервер на порту 80 (http) и перенаправить все запросы на порт 443 (https). Парус сначала компилирует файл config / bootstrap.js перед тем, как поднять сервер. Здесь мы можем запустить наш экспресс-сервер через порт 80.

В config / bootstrap.js (создать http-сервер и перенаправить весь запрос на 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();
};

Теперь вы можете посетить http://www.yourdomain.com , он будет перенаправлен на https://www.yourdomain.com

Нищит Дханани
источник
8

Используйте экспресс-блокировку: бесплатный SSL, автоматический HTTPS

Greenlock управляет выдачей и продлением сертификата (через Let's Encrypt) и перенаправлением 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: '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

Посмотрите демонстрацию QuickStart: https://youtu.be/e8vaR4CEZ5s

Для Localhost

Просто отвечаю на это заранее, потому что это общий вопрос для продолжения:

Вы не можете иметь SSL-сертификаты на локальном хосте. Тем не менее, вы можете использовать что-то вроде Telebit, что позволит вам запускать локальные приложения как настоящие.

Вы также можете использовать частные домены с Greenlock через вызовы DNS-01, которые упоминаются в README вместе с различными плагинами, которые его поддерживают.

Нестандартные порты (т.е. нет 80/443)

Прочтите заметку выше о localhost - вы не можете использовать нестандартные порты с Let's Encrypt.

Однако вы можете выставить свои внутренние нестандартные порты как внешние стандартные порты через переадресацию портов, sni-route или использовать что-то вроде Telebit, которое выполняет SNI-маршрутизацию и переадресацию портов / ретрансляцию для вас.

Вы также можете использовать вызовы DNS-01, в этом случае вам вообще не нужно будет открывать порты, и вы также можете защищать домены в частных сетях.

CoolAJ86
источник
«Вы не можете иметь SSL-сертификаты на локальном хосте». - У меня SSL работает над моим приложением React на localhost. Пришел сюда в поисках, как заставить его работать в Экспрессе. React - это мой фронтенд, а Express - мой бэкэнд. Нужно, чтобы он работал на Stripe, так как мой пост в Stripe должен быть в SSL. Должно быть очевидно, но в localhost я тестирую, и на сервере это будет производство.
Taersious
Исправление: «Вы не можете иметь действительные сертификаты SSL на локальном хосте».
CoolAJ86
6

Вот как это работает для меня. Используемое перенаправление также перенаправит все обычные 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

Это мой рабочий код для экспресс 4.0 .

Экспресс 4.0 сильно отличается от 3.0 и других.

4.0 у вас есть файл / bin / www, который вы собираетесь добавить https здесь.

«Запуск npm» - это стандартный способ запуска сервера Express 4.0.

Функция readFileSync () должна использовать __dirname для получения текущего каталога

в то время как require () использует ./ ссылается на текущий каталог.

Сначала вы помещаете файл private.key и public.cert в папку / bin. Это та же папка, что и в файле WWW .

hoogw
источник