developer tip

Heroku NodeJS http에서 https SSL로 강제 리디렉션

optionbox 2020. 8. 20. 08:11
반응형

Heroku NodeJS http에서 https SSL로 강제 리디렉션


https를 사용하는 노드에서 express를 사용하여 heroku에서 응용 프로그램을 실행하고 있습니다. 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);

오늘, 현재 2014년 10월 10 , 사용 Heroku가 삼나무 스택ExpressJS ~ 3.4.4 , 여기에 코드의 작업 집합이다.

여기서 기억해야 할 주요 사항은 Heroku에 배포하고 있다는 것입니다. SSL 종료는 암호화 된 트래픽이 노드 앱에 도달하기 전에로드 밸런서에서 발생합니다. req.headers [ 'x-forwarded-proto'] === 'https'를 사용하여 https를 사용하여 요청했는지 여부를 테스트 할 수 있습니다.

다른 환경에서 호스팅하는 경우처럼 앱 등 내부에 로컬 SSL 인증서를 갖는 것에 대해 걱정할 필요가 없습니다. 그러나 자체 인증서, 하위 도메인 등을 사용하는 경우 먼저 Heroku 추가 기능을 통해 SSL 추가 기능을 적용해야합니다.

그런 다음 다음을 추가하여 HTTPS가 아닌 다른 항목에서 HTTPS로 리디렉션합니다. 이것은 위에서 받아 들여진 대답에 매우 가깝지만 다음과 같습니다.

  1. "app.use"를 사용하는지 확인합니다 (get뿐만 아니라 모든 작업에 대해)
  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();
  }
};

Then reference from config/policies.js along with any other policies, e.g:

'*': ['authenticated', 'enforceSsl']


The answer is to use the header of 'x-forwarded-proto' that Heroku passes forward as it does it's proxy thingamabob. (side note: They pass several other x- variables too that may be handy, check them out).

My code:

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

Thanks Brandon, was just waiting for that 6 hour delay thing that wouldn't let me answer my own question.


The accepted answer has a hardcoded domain in it, which isn't too good if you have the same code on several domains (eg: dev-yourapp.com, test-yourapp.com, yourapp.com).

Use this instead:

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


I've written a small node module that enforces SSL on express projects. It works both in standard situations and in case of reverse proxies (Heroku, nodejitsu, etc.)

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


If you want to test out the x-forwarded-proto header on your localhost, you can use nginx to setup a vhost file that proxies all of the requests to your node app. Your nginx vhost config file might look like this

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

The important bits here are that you are proxying all requests to localhost port 3000 (this is where your node app is running) and you are setting up a bunch of headers including X-Forwarded-Proto

Then in your app detect that header as usual

Express

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

Hosts

Finally you have to add this line to your hosts file

127.0.0.1 dummy.com

If you are using cloudflare.com as CDN in combination with heroku, you can enable automatic ssl redirect within cloudflare easily like this:

  1. Login and go to your dashboard

  2. Select Page Rules

    Select Page Rules

  3. Add your domain, e.g. www.example.com and switch always use https to on Switch always use https to on

Loopback users can use a slightly adapted version of arcseldon answer as middleware:

server/middleware/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());

You should take a look at heroku-ssl-redirect. It works like a charm!

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

A more express specific way to do this.

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

Checking the protocol in the X-Forwarded-Proto header works fine on Heroku, just like Derek has pointed out. For what it's worth, here is a gist of the Express middleware that I use and its corresponding test.


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

참고URL : https://stackoverflow.com/questions/7185074/heroku-nodejs-http-to-https-ssl-forced-redirect

반응형