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


105

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

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 2011 년

1
좋아 그래서 나는 당신이 이와 같이 https를 확인하고 필요한 경우 리디렉션한다는 것을 알게되었습니다. 그러나 도메인 이름 공급자와 함께 DNS 수준에서 경로를 다시 지정하는 방법이 있습니까? 따라서 브라우저가 DNS를 확인하기 전에 이미 https에 있습니다. 이 접근 방식을 사용하면 리디렉션에 대한 지식을 고려할 때 http를 통해 요청한 다음 https를 통해 다시 요청하는 것으로 생각합니다. 따라서 민감한 데이터가 전송되면 http를 통해 한 번 전송되었습니다. 그런 다음 https를 통해. 어느 정도 목적을 무너 뜨립니다. 내가 틀렸다면 알려주세요.
Muhammad Umer

@MuhammadUmer, 당신의 추론이 여기에있는 것 같습니다. 더 많은 것을 발견 했습니까?
Karoh

나는 단순히 nginx로 작동하는 네임 서버로 cloudflare를 사용했으며 토글 버튼을 클릭하여 SSL 버전으로 리디렉션 할 수 있습니다. 또한 다음과 같이 할 수 있습니다. developer.mozilla.org/en-US/docs/Web/HTTP/Headers/… 게다가 일반적으로 아무도 데이터를 즉시 보내지 않고 일반적으로 양식에 도착한 다음 제출합니다. 그래서 서버 측 코드, DNS 서버, HTTP 헤더, 자바 스크립트 확인할 수 리디렉션에에 HTTPS developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
무하마드 Umer

답변:


107

오늘, 현재 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();
  }
};

그런 다음 config / policies.js에서 다른 정책과 함께 참조하십시오. 예 :

'*': [ '인증 됨', 'enforceSsl']


1
sails 정책 사용에 대한 참고 사항 : sailsjs.org/#/documentation/concepts/Policies에 설명 된 대로 : "기본 정책 매핑은"계단식 "또는"아래로 내려가는 "것이 아닙니다. 컨트롤러의 작업에 대해 지정된 매핑이 기본 매핑을 재정의합니다. " 즉, 특정 컨트롤러 / 작업에 대한 다른 정책이있는 즉시 해당 컨트롤러 / 작업에 'enforceSsl'을 추가해야합니다.
Manuel Darveau

2
"다음 표에는 Express 4의 작지만 중요한 다른 변경 사항이 나열되어 있습니다. ... app.configure () 함수가 제거되었습니다. process.env.NODE_ENV 또는 app.get ( 'env') 함수를 사용하여 환경을 감지하고 이에 따라 응용 프로그램을 구성합니다. "
케빈 윌러

9
또한 res.redirect기본값은 302 리디렉션 (최소한 Express 4.x)입니다. SEO 및 캐싱 이유로 인해 대신 301 리디렉션을 원할 것입니다. 함께 해당 라인을 교체return res.redirect(301, ['https://', req.get('Host'), req.url].join(''));
케빈 휠러

6
참고 : Express 4.x에서 app.configure선을 제거 하고 내면의 물약 만 사용하십시오. app.configure레거시 코드이며 더 이상 Express에 포함되지 않습니다.
Augie Gardner 2016

96

대답은 Heroku가 프록시 thingamabob처럼 전달하는 '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 */
})

고마워 Brandon, 내 질문에 답할 수없는 6 시간의 지연을 기다리고 있었어.


4
이것은 GET통과 하는 것 이외의 다른 방법을 허용하지 않습니까?
Jed Schmidt

1
@Aaron : 글쎄요, POST 요청을 투명하게 리디렉션하면 잠재적으로 정보를 잃을 수 있습니다. http에 대한 GET 이외의 요청에 대해 400을 반환해야한다고 생각합니다.
theodorton 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/


잘 작동합니다. 나는 두노 난 그냥 교체 한 이유 req.hostnamereq.headers.host내가 4.2에있어 어쩌면 익스프레스 버전
제레미 Piednoel


6

x-forwarded-protolocalhost 에서 헤더 를 테스트하려는 경우 nginx 를 사용 하여 모든 요청을 노드 앱에 프록시하는 가상 호스트 파일을 설정할 수 있습니다 . nginx 가상 호스트 구성 파일은 다음과 같습니다.

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

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파일 에 추가해야 합니다.

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

heroku와 함께 cloudflare.com을 CDN으로 사용하는 경우 다음과 같이 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

이것은이를 수행하는보다 Express 특정 방법입니다.

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.