Как заставить SSL / https в Express.js - PullRequest
53 голосов
/ 22 декабря 2011

Я пытаюсь создать промежуточное программное обеспечение для Express.js для перенаправления всего незащищенного (порт 80) трафика на защищенный порт SSL (443). К сожалению, в запросе Express.js нет информации, позволяющей определить, поступил ли запрос по http или https.

Одним из решений будет перенаправление каждого запроса, но это не вариант для меня.

Примечания:

  1. Нет возможности обработать его с помощью Apache или чего-то еще. должен иметь в узле.

  2. В приложении можно запустить только один сервер.

Как бы вы решили это?

Ответы [ 8 ]

43 голосов
/ 30 июня 2015

На тот случай, если вы используете Heroku и просто хотите перенаправить на HTTPS независимо от порта, вот промежуточное программное обеспечение, которое мы используем.

Перенаправление не беспокоит, если вы разрабатываетелокально.

function requireHTTPS(req, res, next) {
  // The 'x-forwarded-proto' check is for Heroku
  if (!req.secure && req.get('x-forwarded-proto') !== 'https' && process.env.NODE_ENV !== "development") {
    return res.redirect('https://' + req.get('host') + req.url);
  }
  next();
}

Вы можете использовать его с Express (2.x и 4.x) следующим образом:

app.use(requireHTTPS);
26 голосов
/ 14 июня 2012

Хотя вопрос выглядит годовалым, я бы хотел ответить, так как он может помочь другим. Это на самом деле очень просто с последней версией expressjs (2.x). Сначала создайте ключ и подтвердите, используя этот код

openssl genrsa -out ssl-key.pem 1024

$ openssl req -new -key ssl-key.pem -out certrequest.csr .. куча подсказок

$ openssl x509 -req -in certrequest.csr -signkey ssl-key.pem -out ssl-cert.pem

Храните файлы сертификатов и ключей в папке, содержащей app.js. Затем отредактируйте файл app.js и напишите следующий код перед express.createServer ()

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

var sslkey = fs.readFileSync('ssl-key.pem');
var sslcert = fs.readFileSync('ssl-cert.pem')

var options = {
    key: sslkey,
    cert: sslcert
};

Теперь передайте объект options в функцию createServer ()

express.createServer(options);

Готово!

21 голосов
/ 26 декабря 2011

Во-первых, давайте посмотрим, смогу ли я прояснить проблему.Вы ограничены одним (1) процессом node.js, но этот процесс может прослушивать два (2) сетевых порта, 80 и 443, верно?(Когда вы говорите один сервер, неясно, имеете ли вы в виду один процесс или только один сетевой порт.)как-то ваши клиенты подключаются не к тому порту.Это причудливый крайний случай, потому что по умолчанию клиенты отправляют HTTP-запросы на порт 80 и HTTPS на порт 443. И когда я говорю «по умолчанию», я имею в виду, что в URL-адреса не включены конкретные порты.Поэтому, если вы явно не используете перекрещенные URL-адреса, такие как http://example.com:443 и https://example.com:80,, у вас действительно не должно быть никакого перекрещенного трафика, попадающего на ваш сайт.Но так как вы задали вопрос, я полагаю, что он у вас есть, хотя я уверен, что вы используете нестандартные порты, а не значения по умолчанию 80/443.

Итак, для справки: ДА некоторые веб-серверы обрабатывают этодостаточно хорошоНапример, если вы введете http://example.com:443 для nginx, он ответит HTTP 400 «Плохой запрос», указывающий «Простой HTTP-запрос был отправлен на порт HTTPS».ДА, вы можете прослушивать 80 и 443 из одного и того же процесса node.js.Вам просто нужно создать 2 отдельных экземпляра express.createServer(), так что это не проблема.Вот простая программа, демонстрирующая обработку обоих протоколов.

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

var http = express.createServer();

var httpsOptions = {
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
};

var https = express.createServer(httpsOptions);

http.all('*', function(req, res) {
  console.log("HTTP: " + req.url);
  return res.redirect("https://" + req.headers["host"] + req.url);
});

http.error(function(error, req, res, next) {
  return console.log("HTTP error " + error + ", " + req.url);
});

https.error(function(error, req, res, next) {
  return console.log("HTTPS error " + error + ", " + req.url);
});

https.all('*', function(req, res) {
  console.log("HTTPS: " + req.url);
  return res.send("Hello, World!");
});

http.listen(80);

И я могу проверить это через cURL следующим образом:

$ curl --include --silent http://localhost/foo
HTTP/1.1 302 Moved Temporarily
X-Powered-By: Express
Content-Type: text/html
Location: https://localhost/foo
Connection: keep-alive
Transfer-Encoding: chunked

<p>Moved Temporarily. Redirecting to <a href="https://localhost/foo">https://localhost/foo</a></p>

$ curl --include --silent --insecure https://localhost:443/foo
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive

Hello, World!%

И показать перенаправление с HTTP на HTTPS ...

curl --include --silent --location --insecure 'http://localhost/foo?bar=bux'
HTTP/1.1 302 Moved Temporarily
X-Powered-By: Express
Content-Type: text/html
Location: https://localhost/foo?bar=bux
Connection: keep-alive
Transfer-Encoding: chunked

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive

Hello, World!%

Так что это будет работать, чтобы обслуживать оба протокола для обычного случая и правильно перенаправлять.Тем не менее, крест-накрест не работают вообще.Я полагаю, что перекрещенный запрос, попадающий на сервер экспресс-доставки, не будет маршрутизироваться через стек промежуточного программного обеспечения, поскольку с самого начала он будет рассматриваться как ошибка и даже не сможет правильно проанализировать URI запроса, что необходимо дляотправить его через цепочку промежуточного программного обеспечения маршрута.Я думаю, что экспресс-стек их даже не получает, потому что они не являются допустимыми запросами, поэтому они игнорируются где-то в стеке узлов TCP.Вероятно, можно написать сервер для этого, и там уже может быть модуль, но вам придется написать его непосредственно на уровне TCP.И вам придется обнаружить обычный HTTP-запрос в первом фрагменте данных клиента, который попадает на TCP-порт, и подключить это соединение к HTTP-серверу вместо обычного рукопожатия TLS.

Когда я выполняю любое из этих действиймои экспресс-обработчики ошибок НЕ вызываются.

curl  --insecure https://localhost:80/foo
curl: (35) Unknown SSL protocol error in connection to localhost:80

curl http://localhost:443/foo
curl: (52) Empty reply from server
10 голосов
/ 12 декабря 2013

На основании ответа Элиаса, но со встроенным кодом. Это работает, если у вас есть узел позади nginx или балансировщик нагрузки. Nginx или балансировщик нагрузки всегда будут попадать на узел со старым http, но он устанавливает заголовок, чтобы вы могли различать.

app.use(function(req, res, next) {
  var schema = req.headers['x-forwarded-proto'];

  if (schema === 'https') {
    // Already https; don't do anything special.
    next();
  }
  else {
    // Redirect to https.
    res.redirect('https://' + req.headers.host + req.url);
  }
});
3 голосов
/ 27 декабря 2011

http.createServer (app.handle) .listen (80)

https.createServer (параметры, app.handle) .listen (443)

для экспресса 2x

2 голосов
/ 17 января 2017

Попробуйте этот пример:

var express = require('express');
        var app = express();
        // set up a route to redirect http to https
        app.use(function (req, res, next) {
        if (!/https/.test(req.protocol)) {
            res.redirect("https://" + req.headers.host + req.url);
        } else {
            return next();
        }
        });
        var webServer = app.listen(port, function () {
            console.log('Listening on port %d', webServer.address().port);
        });
2 голосов
/ 14 марта 2012

Этот код выглядит так, как будто он делает то, что вам нужно: https://gist.github.com/903596

0 голосов
/ 28 декабря 2011

Так как я работал над nginx, у меня был доступ к свойству заголовка x-forwarded-proto, чтобы я мог написать крошечное промежуточное ПО для перенаправления всего трафика, как описано здесь: http://elias.kg/post/14971446990/force-ssl-with-express-js-on-heroku-nginx

Редактировать: Обновлен URL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...