Heroku NodeJS http到https ssl强制重定向

时间:2011-08-25 04:15:46

标签: redirect ssl node.js https heroku

我在heroku上运行了一个应用程序,并使用https在节点上运行。如何识别协议以强制重定向到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);

13 个答案:

答案 0 :(得分:101)

截至今天, 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.   
  3. 将forceSsl逻辑显式外部化为声明的函数
  4.   
  5. 不使用' *'使用" app.use" - 当我这真的失败了   测试了它。
  6.   
  7. 在这里,我只想在生产中使用SSL。 (根据您的需要改变)
  8.   

代码:

 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 :(得分:93)

答案是使用Heroku传递的'x-forwarded-proto'的标题,因为它是代理的thingamabob。 (旁注:他们也传递了其他几个可能很方便的x变量,check them out)。

我的代码:

/* 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小时延迟的事情。

答案 2 :(得分:21)

接受的答案中包含一个硬编码域,如果您在多个域上使用相同的代码(例如: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/

答案 3 :(得分:16)

我编写了一个小型节点模块,可以对快速项目强制执行SSL。它既适用于标准情况,也适用于反向代理(Heroku,nodejitsu等)

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

答案 4 :(得分: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

答案 5 :(得分:4)

如果您使用cloudflare.com作为CDN与heroku结合使用,您可以轻松地在cloudflare中启用自动ssl重定向:

  1. 登录并转到信息中心

  2. 选择页面规则

    Select Page Rules

  3. 添加您的域名,例如www.example.com和交换机始终使用https打开 Switch always use https to on

答案 6 :(得分:3)

Loopback用户可以使用稍微改编版的arcseldon answer作为中间件:

服务器/中间件/ 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.js

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

答案 7 :(得分:2)

你应该看看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);

答案 8 :(得分:1)

我正在使用 Vue、Heroku 并且遇到了同样的问题:

我如下更新了我的 server.js,我不再碰它了,因为它正在工作:) :

const serveStatic = require('serve-static')
const sts = require('strict-transport-security');
const path = require('path')

var express = require("express");

require("dotenv").config();
var history = require("connect-history-api-fallback");

const app = express()
const globalSTS = sts.getSTS({'max-age':{'days': 365}});
app.use(globalSTS);

app.use(
  history({
    verbose: true
  })
);

app.use((req, res, next) => {
  if (req.header('x-forwarded-proto') !== 'https') {
    res.redirect(`https://${req.header('host')}${req.url}`)
  } else {
    next();
  }
});

app.use('/', serveStatic(path.join(__dirname, '/dist')));
app.get(/.*/, function (req, res) {
res.sendFile(path.join(__dirname, '/dist/index.html'))
})

const port = process.env.PORT || 8080
app.listen(port)
console.log(`app is listening on port: ${port}`)

答案 9 :(得分:0)

检查X-Forwarded-Proto标头中的协议在Heroku上运行正常,就像Derek指出的那样。对于它的价值,here is a gist我使用的Express中间件及其相应的测试。

答案 10 :(得分: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 */
  }
});

答案 11 :(得分:0)

更明确的具体方法。

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

答案 12 :(得分: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()
});