Heroku NodeJS http для https ssl примусового переадресації


105

У мене є додаток, що працює і працює на heroku з експресом по вузлу з 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);

6
Підтримка Heroku відповіла на моє вище запитання, і я вже не знайшов його розміщеним тут, тому думав, що опублікую його на публіці та поділюсь знаннями. Вони передають багато інформації про вихідний запит із заголовками запиту з префіксом "x-". Ось код, який я зараз використовую (у верхній частині моїх визначень маршруту):app.get('*',function(req,res,next){ if(req.headers['x-forwarded-proto']!='https') res.redirect('https://mypreferreddomain.com'+req.url) else next() })
Дерек Бреденштайнер,

1
Ок, я отримую, що ви перевіряєте наявність https, як це, і перенаправляєте, якщо потрібно. Але чи є спосіб перенаправити на рівні dns з постачальником послуг доменних імен. Отже, перш ніж браузер вирішить DNS, він уже на https. Тому що з таким підходом є те, що я думаю, враховуючи мої знання про переадресації, що раз запит робиться через http, а потім знову через https. Тож якщо конфіденційні дані були надіслані, то вони надсилалися через http один раз. потім через https. Який вид перемагає мету. Будь ласка, дайте мені знати, якщо я помиляюся.
Мухаммед Умер

@MuhammadUmer, ваші міркування, схоже, тут, ви коли-небудь дізналися більше?
Карох

Я просто використав cloudflare як сервер імен, який працює як nginx, і дозволяє мені перенаправляти на версію ssl, просто натиснувши кнопку перемикання. також ви можете це зробити: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/… Крім того, зазвичай ніхто не надсилає дані відразу, вони зазвичай прибувають на бланку і потім подають. так що на стороні сервера код, dns сервер, http заголовок, javascript ви можете перевірити та перенаправити на https developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
Мухаммед Умер

Відповіді:


107

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

Тут головне пам’ятати, що ми МОЄМО розгортаємось до Хероку. Закінчення 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). Ви можете просто створити політику (impoceSsl.js) всередині api / policy:

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 / policy.js разом з будь-якими іншими полісами, наприклад:

'*': ['автентифіковано', 'прымуситиSsl']


1
Примітка про використання політики вітрил: Як зазначено в sailsjs.org/#/documentation/concepts/Policies : "Політичні зіставлення за замовчуванням не" каскадуються "і не" схиляються вниз ". " Це означає, що, як тільки у вас з’являться інші політики щодо конкретного контролера / дії, вам доведеться додати «ExecuteSsl» на цей контролер / дії.
Мануель Дарво

2
"У наступній таблиці перераховані інші невеликі, але важливі зміни в Express 4: ... Функція app.configure () була видалена. Використовуйте функцію process.env.NODE_ENV або app.get ('env') для виявлення середовища та конфігуруйте додаток відповідно ".
Кевін Вілер

9
Також зауважте, що res.redirectце налаштування за замовчуванням до перенаправлення 302 (принаймні, у експресі 4.x). З причини SEO та кешування ви, мабуть, хочете переадресацію 301 замість цього. Замініть відповідний рядок наreturn res.redirect(301, ['https://', req.get('Host'), req.url].join(''));
Кевін Уілер

6
Примітка: В Express 4.x, видаліть app.configureрядок і просто використовуйте внутрішнє зілля. app.configureє застарілим кодом і більше не включається в експрес.
Огі Гарднер

96

Відповідь полягає у використанні заголовка "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-годинної затримки, яка не дозволила мені відповісти на моє власне питання.


4
Хіба це не дозволило б використовувати інші методи, ніж GETчерез?
Джед Шмідт

1
@Aaron: Ну, ви потенційно можете втратити інформацію, якщо прозоро переспрямуєте POST-запит. Я думаю, ви повинні повернути 400 за іншими запитами, ніж GET для http.
Теодортон

3
Ви можете кинути && process.env.NODE_ENV === "production"своє умовне, якщо ви хочете, щоб він працював лише у виробничих умовах.
Keepitreal

307 (переспрямовування тим же методом), мабуть, краще, ніж помилка 400.
Бені Чернявський-Паскін

З цією відповіддю існує кілька проблем, див. Наступну відповідь нижче ( stackoverflow.com/a/23894573/14193 ) та оцініть її.
Ніл

22

У прийнятій відповіді міститься домен із твердим кодом, що не надто добре, якщо ви маєте однаковий код у кількох доменах (наприклад: 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-generely/


Добре працює. Я давно, чому мені просто довелося замінити req.hostnameна, req.headers.hostможливо, експрес-версію, мені вже в 4.2
Джеремі П'єднол

16

Я написав невеликий модуль вузлів, який застосовує SSL на експрес-проектах. Він працює як у стандартних ситуаціях, так і у випадку зворотних проксі-серверів (Heroku, nodejitsu тощо)

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


6

Якщо ви хочете перевірити x-forwarded-protoзаголовок на своєму localhost, ви можете використовувати 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;
  }
}

Важливі біти тут полягають у тому, що ви звертаєтесь до всіх запитів до порту localhost 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

Слід поглянути на 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);

4

Якщо ви використовуєте cloudflare.com як CDN у поєднанні з heroku, ви можете ввімкнути автоматичне перенаправлення ssl у cloudflare легко так:

  1. Увійдіть та перейдіть на панель приладів

  2. Виберіть Правила сторінки

    Виберіть Правила сторінки

  3. Додайте свій домен, наприклад, www.example.com та перемикайте завжди, щоб використовувати https Перемикач завжди використовувати https на увімкнено

3

Користувачі циклу можуть використовувати трохи адаптовану версію відповіді 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 / server.js

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

2

Це більш експрес-специфічний спосіб зробити це.

app.enable('trust proxy');
app.use('*', (req, res, next) => {
  if (req.secure) {
    return next();
  }
  res.redirect(`https://${req.hostname}${req.url}`);
});

0
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

За допомогою програми app.use та динамічного URL-адреси. Для мене працює як локально, так і на Heroku

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

-1

Перевірка протоколу в заголовку X-Forwarded-Proto добре працює на Heroku, як і Дерек. Для чого це варто, ось суть програмного забезпечення Express, яке я використовую, та його відповідний тест.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.