Подтвердить что ты не робот

Как заставить SSL/https в Express.js

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

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

Примечания:

  • Нет возможности справиться с Apache или чем-то еще. Он имеет в node.

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

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

4b9b3361

Ответ 1

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

Изменить: обновлен URL

Ответ 2

Хотя вопрос выглядит год назад, я хотел бы ответить, поскольку это может помочь другим. Его действительно просто с последней версией 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);

Готово!

Ответ 3

Во-первых, позвольте мне посмотреть, могу ли я прояснить проблему. Вы ограничены одним (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-запрос, что необходимо для отправьте его через цепочку промежуточного программного обеспечения маршрута. Экспресс-стек даже не получил их, я думаю, потому что они не являются допустимыми запросами, поэтому они игнорируются где-то в стеке node 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

Ответ 4

На всякий случай, если вы размещаете на 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);

Ответ 5

На основе ответа Elias, но с встроенным кодом. Это работает, если у вас есть node за nginx или балансировщик нагрузки. Nginx или балансировщик всегда будут нажимать node на простой старый 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);
  }
});

Ответ 6

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

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

для выражения 2x

Ответ 7

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

Ответ 8

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

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