Heroku NodeJS http'den https ssl'ye zorunlu yönlendirme


105

Https ile düğümde ekspres ile heroku üzerinde çalışan bir uygulamam var. Heroku'da nodejs ile https'ye yönlendirmeye zorlamak için protokolü nasıl tanımlarım?

Uygulamam sadece basit bir http sunucusu, (henüz) heroku'nun ona https istekleri gönderdiğinin farkında değil:

/* 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 desteği yukarıdaki sorumu yanıtladı ve bunu buraya zaten gönderilmiş bulamadım, bu yüzden onu herkese açık olarak paylaşıp bilgiyi paylaşacağımı düşündüm. Orijinal istek hakkında pek çok bilgiyi, başında 'x-' bulunan istek başlıklarıyla iletirler. İşte şimdi kullandığım kod (rota tanımlarımın en üstünde):app.get('*',function(req,res,next){ if(req.headers['x-forwarded-proto']!='https') res.redirect('https://mypreferreddomain.com'+req.url) else next() })
Derek Bredensteiner

1
Tamam, bunun gibi https'yi kontrol etmenizi ve gerekirse yeniden yönlendirmenizi anlıyorum. Ancak alan adı sağlayıcınızla dns düzeyinde yeniden yönlendirme yapmanın bir yolu var mı? Bu yüzden tarayıcı DNS'yi çözmeden önce zaten https'de. Çünkü bu yaklaşımla, yönlendirmelerle ilgili bilgim göz önüne alındığında, bir kez talep http üzerinden ve sonra tekrar https üzerinden yapıldığını düşünüyorum. Dolayısıyla, hassas veriler gönderildiyse, http üzerinden bir kez gönderildi. sonra https üzerinden. Hangisi amacı bozuyor. Yanılıyorsam lütfen bana bildirin.
Muhammed Umer

@MuhammadUmer, mantığınız burada poin üzerinde görünüyor, daha fazlasını keşfettiniz mi?
Karoh

nginx olarak çalışan ad sunucusu olarak cloudflare kullandım ve geçiş düğmesine tıklayarak ssl sürümüne yönlendirmeme izin veriyor. Ayrıca şunu da yapabilirsiniz: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/… Ayrıca, genellikle hiç kimse verileri hemen göndermez, genellikle forma gelir ve sonra gönderir. bu nedenle sunucu tarafı kodu, dns sunucusu, http başlığı, javascript üzerinde kontrol edebilir ve https developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
Muhammad Umer

Yanıtlar:


107

Bugün, 10 Ekim 2014 itibariyle , Heroku Cedar yığını ve ExpressJS ~ 3.4.4 kullanılarak , işte çalışan bir kod seti.

Burada hatırlanması gereken en önemli şey, Heroku'ya konuşlandırmaktayız. SSL sonlandırma, şifreli trafik düğüm uygulamanıza ulaşmadan önce yük dengeleyicide gerçekleşir. İstek yapmak için https'nin kullanılıp kullanılmadığını req.headers ['x-forwarded-proto'] === 'https' ile test etmek mümkündür .

Başka ortamlarda barındırıyor olabileceğiniz gibi, uygulama içinde yerel SSL sertifikaları vb. İle ilgilenmemize gerek yok. Ancak, kendi sertifikanızı, alt alan adlarınızı vb. Kullanıyorsanız öncelikle Heroku Eklentileri aracılığıyla bir SSL Eklentisi uygulamanız gerekir.

Ardından, yönlendirmeyi HTTPS'den HTTPS'ye başka herhangi bir şeyden yapmak için aşağıdakileri ekleyin. Bu, yukarıda kabul edilen cevaba çok yakın, ancak:

  1. "App.use" kullanmanızı sağlar (yalnızca alma değil tüm eylemler için)
  2. ForceSsl mantığını açık bir şekilde bildirilmiş bir işleve dışsallaştırır
  3. "App.use" ile '*' kullanmıyor - bu gerçekten test ettiğimde başarısız oldu.
  4. Burada sadece üretimde SSL istiyorum. (İhtiyaçlarınıza göre değiştirin)

Kod:

 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) kullanıcıları için not. Api / policies içinde basitçe bir politika (forceSsl.js) oluşturabilirsiniz:

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

Ardından, diğer politikalarla birlikte config / policies.js'den referans alın, örneğin:

'*': ['doğrulanmış', 'zorlaSsl']


1
Bir yelken politikası kullanma hakkında bir not: sailsjs.org/#/documentation/concepts/Policies'de belirtildiği gibi : "Varsayılan politika eşlemeleri" basamaklı "veya" aşağı damlama "yapmaz. Denetleyicinin eylemleri için belirtilen eşlemeler, varsayılan eşlemeyi geçersiz kılar. " Bu, belirli bir denetleyici / eylem için başka politikalarınız olur olmaz, bu denetleyiciye / eyleme 'forceSsl' eklediğinizden emin olmanız gerektiği anlamına gelir.
Manuel Darveau

2
"Aşağıdaki tablo, Express 4'teki diğer küçük ama önemli değişiklikleri listeler: ... app.configure () işlevi kaldırıldı. Ortamı algılamak için process.env.NODE_ENV veya app.get ('env') işlevini kullanın ve uygulamayı uygun şekilde yapılandırın. "
Kevin Wheeler

9
Ayrıca, res.redirectbunun varsayılan olarak 302 yönlendirmesi olduğunu unutmayın (en azından express 4.x'te). SEO ve önbelleğe alma nedenleriyle, muhtemelen bunun yerine bir 301 yönlendirmesi istiyorsunuz. Karşılık gelen satırı şu ile değiştirinreturn res.redirect(301, ['https://', req.get('Host'), req.url].join(''));
Kevin Wheeler

6
Not: Sırayı Express 4.xkaldırın app.configureve sadece iç iksiri kullanın. app.configureeski bir koddur ve artık express'e dahil değildir.
Augie Gardner

96

Cevap, Heroku'nun vekil şey olduğu gibi ilettiği 'x-forwarded-proto' başlığını kullanmaktır. (yan not: Kullanışlı olabilecek birkaç başka x değişkenini de aktarırlar, kontrol edin ).

Kodum:

/* 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 */
})

Teşekkürler Brandon, kendi sorumu cevaplamama izin vermeyen 6 saatlik gecikme olayını bekliyordum.


4
bu, GETgeçmekten başka yöntemlere izin vermez mi?
Jed Schmidt

1
@Aaron: Bir POST isteğini şeffaf bir şekilde yeniden yönlendirirseniz, potansiyel olarak bilgileri kaybedersiniz. Bence http için GET dışındaki isteklerde 400 döndürmeniz gerekir.
theodorton

3
&& process.env.NODE_ENV === "production"Yalnızca üretim ortamınızda çalışmasını istiyorsanız, koşullarınıza bir atabilirsiniz .
keepitreal

307 (aynı yöntemle yeniden yönlendirme) muhtemelen 400 hatasından daha iyidir.
Beni Cherniavsky-Paskin

Bu yanıtla ilgili birden fazla sorun var, aşağıdaki sonraki yanıta bakın ( stackoverflow.com/a/23894573/14193 ) ve bunu düşürün.
Neil

22

Kabul edilen yanıtın içinde sabit kodlanmış bir etki alanı vardır; bu, birden fazla etki alanında aynı koda sahipseniz çok iyi değildir (örneğin: dev-yourapp.com, test-yourapp.com, yourapp.com).

Bunun yerine şunu kullanın:

/* 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/


Güzel çalışıyor. Ben duno ben sadece değiştirmek zorunda neden req.hostnameolan req.headers.hosti 4.2 olduğum belki ekspres sürümü
Jeremy Piednoel


6

x-forwarded-protoBaşlığı localhost'unuzda test etmek istiyorsanız, tüm istekleri node uygulamanıza vekalet eden bir vhost dosyası kurmak için nginx'i kullanabilirsiniz . Nginx vhost yapılandırma dosyanız şöyle görünebilir

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

Buradaki önemli kısımlar, tüm istekleri localhost port 3000'e (düğüm uygulamanızın çalıştığı yer) proxy yapıyor olmanız ve aşağıdakiler dahil olmak üzere bir grup başlık ayarlamanızdır. X-Forwarded-Proto

Ardından uygulamanızda bu başlığı her zamanki gibi algılar

Ekspres

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

Koa

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

Barındırıcılar

Sonunda bu satırı hostsdosyanıza eklemelisiniz

127.0.0.1 dummy.com

6

Heroku-ssl-yönlendirmesine bir göz atmalısınız . Mucizevi şekilde çalışır!

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'u heroku ile birlikte CDN olarak kullanıyorsanız, cloudflare içinde otomatik ssl yönlendirmesini şu şekilde kolayca etkinleştirebilirsiniz:

  1. Giriş yapın ve kontrol panelinize gidin

  2. Sayfa Kurallarını Seçin

    Sayfa Kurallarını Seçin

  3. Alanınızı ekleyin, ör. Www.example.com ve her zaman https kullan seçeneğini açık olarak değiştirin Her zaman https kullan ayarını açık olarak değiştirin

3

Geri döngü kullanıcıları, ara yazılım olarak arcseldon yanıtının biraz uyarlanmış bir sürümünü kullanabilir:

sunucu / ara yazılım / 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

Bu, bunu yapmanın daha Express'e özgü bir yoludur.

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 ve dinamik url ile. Benim için hem yerelde hem de Heroku'da çalışıyor

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 başlığındaki protokolü kontrol etmek, Tıpkı Derek'in işaret ettiği gibi Heroku'da iyi çalışıyor. Değeri ne olursa olsun, burada kullandığım Express ara yazılımın ve ilgili testinin bir özeti var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.