Heroku NodeJS httpからhttps sslへの強制リダイレクト


105

私はherokuでアプリケーションを実行していて、httpsのノードでExpressを使用しています。herokuのnodejsでhttpsへのリダイレクトを強制するプロトコルをどのように識別しますか?

私のアプリは単純な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() })
Derek Bredensteiner '25

1
わかりましたので、このようなhttpsをチェックし、必要に応じてリダイレクトするようにします。しかし、ドメイン名プロバイダーを使用してDNSレベルで再ルーティングする方法はありますか?したがって、ブラウザがDNSを解決する前は、すでにhttpsになっています。このアプローチでは、リダイレクトに関する私の知識があれば、一度リクエストがhttpを介して行われ、次にhttpsを介して行われるためです。したがって、機密データが送信された場合、それはhttp経由で1回送信されました。次にhttpsを介して。どちらが目的を打ち負かすのでしょう。私が間違っているかどうか私に知らせてください。
ムハンマドウメール2015年

@MuhammadUmer、あなたの推論はここで苦痛に思われます、あなたはもっと発見したことがありますか?
Karoh

nginxとして機能するネームサーバーとしてcloudflareを単に使用し、トグルボタンをクリックするだけでsslバージョンにリダイレクトできます。 また、これを実行することもできます:developer.mozilla.org/en-US/docs/Web/HTTP/Headers/…さらに、通常、誰もすぐにデータを送信しないため、通常はフォームに着陸して送信します。サーバー側のコード、dnsサーバー、httpヘッダー、javascriptでは、https developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
Muhammad Umer

回答:


107

本日2014年10月10日現在Heroku CedarスタックExpressJS〜3.4.4を使用して、次のワーキングコードセットをご覧ください。

ここで覚えておくべき主なことは、Herokuにデプロイしているということです。SSL終了は、暗号化されたトラフィックがノードアプリに到達する前に、ロードバランサーで発生します。req.headers ['x-forwarded-proto'] === 'https'を使用して、リクエストにhttpsが使用されたかどうかをテストすることができます

他の環境でホストしている場合のように、アプリ内にローカルSSL証明書があることを気にする必要はありません。ただし、独自の証明書、サブドメインなどを使用している場合は、最初にHerokuアドオンを介してSSLアドオンを適用する必要があります。

次に、以下を追加して、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)ユーザー向けの注意。単純にapi / policies内にポリシー(enforceSsl.js)を作成できます。

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 / policies.jsから他のポリシーとともに参照します。例:

'*':['authenticated'、 'enforceSsl']


1
セイルポリシーの使用に関する注意:sailsjs.org / # / documentation / concepts / Policiesに記載されているように、「デフォルトのポリシーマッピングは「カスケード」または「トリクルダウン」しません。コントローラのアクションに指定されたマッピングは、デフォルトのマッピングをオーバーライドします。 」これは、特定のコントローラー/アクションに他のポリシーがあるとすぐに、それらのコントローラー/アクションに「enforceSsl」を必ず追加する必要があることを意味します。
Manuel Darveau、2015年

2
「次の表に、Express 4のその他の小さな重要な変更を示します。...app.configure()関数は削除されました。process.env.NODE_ENVまたはapp.get( 'env')関数を使用して、環境を検出し、それに応じてアプリを設定してください。」
Kevin Wheeler

9
また、res.redirectこれはデフォルトで302リダイレクトになります(少なくともExpress 4.xでは)。SEOとキャッシュの理由から、おそらく301リダイレクトが必要です。対応する行を次のものに置き換えますreturn res.redirect(301, ['https://', req.get('Host'), req.url].join(''));
Kevin Wheeler

6
注:ではExpress 4.xapp.configure線を削除し、内部のポーションを使用します。 app.configureレガシーコードであり、もはやExpressに含まれていません。
Augie Gardner

96

その答えは、Herokuがプロキシのものと同様に転送する「x-forwarded-proto」のヘッダーを使用することです。(補足:他のいくつかの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介さないようにしませんか?
Jed Schmidt

1
@アーロン:POSTリクエストを透過的にリダイレクトすると、情報が失われる可能性があります。GET for http以外のリクエストでは400を返す必要があると思います。
セオドアン2014年

3
&& process.env.NODE_ENV === "production"本番環境でのみ機能させたい場合は、条件付きのをスローする可能性があります。
keepitreal 2014年

307(同じ方法でリダイレクト)は、おそらく400エラーよりも優れています。
Beni Cherniavsky-Paskin

この回答には複数の問題があります。以下の回答(stackoverflow.com/a/23894573/14193)を参照し、これを評価してください。
Neil

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


うまくいきます。私はちょうど交換していた私はなぜduno req.hostnamereq.headers.host私は4.2によ多分Expressバージョン
ジェレミーPiednoel


6

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

ここで重要なのは、すべてのリクエストを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


4

cloudflare.comをCDNとしてherokuと組み合わせて使用​​している場合は、次のようにcloudflare内で自動sslリダイレクトを簡単に有効にできます。

  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ヘッダーのプロトコルをチェックすることは、Derekが指摘したように、Herokuで正常に機能します。価値があることについてここで私が使用するExpressミドルウェアとそれに対応するテストの要点を示します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.