it-swarm.com.ru

Heroku NodeJS http в https ssl принудительное перенаправление

У меня есть приложение, работающее на герою с экспрессом на узле с https. Как мне определить протокол для принудительного перенаправления на https с nodejs на heroku?

Мое приложение - просто простой http-сервер, оно (пока) не осознает, что heroku отправляет ему запросы https:

/* Heroku provides the port they want you on in this environment variable (hint: it's not 80) */
app.listen(process.env.PORT || 3000);
92
Derek Bredensteiner

Ответ заключается в том, чтобы использовать заголовок «x-forwarded-proto», который Heroku передает вперёд, так как он делает это через посредника. (примечание: они также передают несколько других переменных x, которые могут быть полезны, проверьте их ).

Мой код:

/* At the top, with other redirect methods before other routes */
app.get('*',function(req,res,next){
  if(req.headers['x-forwarded-proto']!='https')
    res.redirect('https://mypreferreddomain.com'+req.url)
  else
    next() /* Continue to other routes if we're not redirecting */
})

Спасибо, Брэндон, просто ждал 6-часовой задержки, которая не позволила бы мне ответить на мой собственный вопрос.

92
Derek Bredensteiner

На сегодняшний день, 10 октября 2014 г. , используя стек Heroku Cedar , и ExpressJS ~ 3.4.4 , вот рабочий набор кода. 

Здесь главное помнить, что мы развертываем на Heroku. Завершение SSL происходит на балансировщике нагрузки, прежде чем зашифрованный трафик достигнет вашего узла приложения. Можно проверить, использовался ли https для выполнения запроса, с помощью req.headers ['x-forwarded-proto'] === 'https' .

Нам не нужно заботиться о наличии локальных SSL-сертификатов внутри приложения и т.д., Как если бы вы размещались в других средах. Тем не менее, вы должны сначала получить надстройку SSL через надстройки Heroku, если используете свой собственный сертификат, поддомен и т.д.

Затем просто добавьте следующее, чтобы выполнить перенаправление с любого другого, кроме HTTPS, на HTTPS. Это очень близко к принятому ответу выше, но: 

  1. Гарантирует, что вы используете "app.use" (для всех действий, а не просто получить)
  2. Явно выводит логику forceSsl в объявленную функцию
  3. Не использует '*' с "app.use" - это фактически не удалось, когда я проверил это. 
  4. Здесь я хочу только SSL в производстве. (Изменить в соответствии с вашими потребностями)

Код:

 var express = require('express'),
   env = process.env.NODE_ENV || 'development';

 var forceSsl = function (req, res, next) {
    if (req.headers['x-forwarded-proto'] !== 'https') {
        return res.redirect(['https://', req.get('Host'), req.url].join(''));
    }
    return next();
 };

 app.configure(function () {

    if (env === 'production') {
        app.use(forceSsl);
    }

    // other configurations etc for express go here...
}

Примечание для пользователей SailsJS (0.10.x). Вы можете просто создать политику (forceceSsl.js) внутри api /icies:

module.exports = function (req, res, next) {
  'use strict';
  if ((req.headers['x-forwarded-proto'] !== 'https') && (process.env.NODE_ENV === 'production')) {
    return res.redirect([
      'https://',
      req.get('Host'),
      req.url
    ].join(''));
  } else {
    next();
  }
};

Затем укажите ссылку на файл config /icies.js вместе с любыми другими политиками, например:

'*': ['authenticated', 'forceceSsl']

98
arcseldon

Принятый ответ содержит жестко закодированный домен, что не слишком хорошо, если у вас есть один и тот же код на нескольких доменах (например, dev-yourapp.com, test-yourapp.com, yourapp.com).

Используйте это вместо:

/* Redirect http to https */
app.get('*', function(req,res,next) {
  if(req.headers['x-forwarded-proto'] != 'https' && process.env.NODE_ENV === 'production')
    res.redirect('https://'+req.hostname+req.url)
  else
    next() /* Continue to other routes if we're not redirecting */
});

https://blog.mako.ai/2016/03/30/redirect-http-to-https-on-heroku-and-node-generally/

20
Joan-Diego Rodriguez

Я написал небольшой узел модуля, который обеспечивает SSL в экспресс-проектах. Работает как в стандартных ситуациях, так и в случае обратных прокси (Heroku, nodejitsu и т.д.)

https://github.com/florianheinemann/express-sslify

16
florian

Если вы хотите проверить заголовок x-forwarded-proto на вашем локальном хосте, вы можете использовать nginx для установки файла vhost, который передает все запросы к вашему приложению узла. Ваш конфигурационный файл nginx vhost может выглядеть так

Nginx

server {
  listen 80;
  listen 443;

  server_name dummy.com;

  ssl on;
  ssl_certificate     /absolute/path/to/public.pem;
  ssl_certificate_key /absolute/path/to/private.pem;

  access_log /var/log/nginx/dummy-access.log;
  error_log /var/log/nginx/dummy-error.log debug;

  # node
  location / {
    proxy_pass http://127.0.0.1:3000/;
    proxy_set_header Host $http_Host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Важными моментами здесь являются то, что вы перенаправляете все запросы на локальный порт 3000 (именно здесь работает приложение вашего узла) и вы устанавливаете несколько заголовков, включая X-Forwarded-Proto

Затем в вашем приложении определите этот заголовок как обычно

Экспресс

var app = express()
  .use(function (req, res, next) {
    if (req.header('x-forwarded-proto') == 'http') {
      res.redirect(301, 'https://' + 'dummy.com' + req.url)
      return
    }
    next()
  })

Коа

var app = koa()
app.use(function* (next) {
  if (this.request.headers['x-forwarded-proto'] == 'http') {
    this.response.redirect('https://' + 'dummy.com' + this.request.url)
    return
  }
  yield next
})

Хосты

Наконец, вы должны добавить эту строку в ваш файл hosts

127.0.0.1 dummy.com
6
simo

Если вы используете cloudflare.com в качестве CDN в сочетании с heroku, вы можете легко включить автоматическое перенаправление ssl в cloudflare следующим образом:

  1. Войдите в систему и перейдите на свою панель инструментов

  2. Выберите Правила страницы

    Select Page Rules

  3. Добавьте свой домен, например, www.example.com и всегда используйте https для включения Switch always use https to on
4
Ben Marten

Пользователи Loopback могут использовать слегка адаптированную версию ответа arcseldon в качестве промежуточного программного обеспечения:

сервера/ПО промежуточного слоя/forcessl.js

module.exports = function() {  
  return function forceSSL(req, res, next) {
    var FORCE_HTTPS = process.env.FORCE_HTTPS || false;
      if (req.headers['x-forwarded-proto'] !== 'https' && FORCE_HTTPS) {
        return res.redirect(['https://', req.get('Host'), req.url].join(''));
      }
      next();
    };
 };

сервер/server.js

var forceSSL = require('./middleware/forcessl.js');
app.use(forceSSL());
3
Bunker

Вы должны взглянуть на heroku-ssl-redirect . Отлично работает!

var sslRedirect = require('heroku-ssl-redirect');
var express = require('express');
var app = express();

// enable ssl redirect
app.use(sslRedirect());

app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);
2
Julien Le Coupanec

Проверка протокола в заголовке X-Forwarded-Proto отлично работает на Heroku, как указывал Дерек. Для чего это стоит, вот Gist промежуточного программного обеспечения Express, которое я использую, и его соответствующий тест.

0
Peter Marklund

Более выразительный конкретный способ сделать это.

  app.enable('trust proxy');
  app.use('*', (req, res, next) => {
    if (req.secure) {
      return next();
    }
    res.redirect(`https://${req.hostname}${req.url}`);
  });
0
denixtry
app.all('*',function(req,res,next){
  if(req.headers['x-forwarded-proto']!='https') {
    res.redirect(`https://${req.get('Host')}`+req.url);
  } else {
    next(); /* Continue to other routes if we're not redirecting */
  }
});
0
Chiedo