2012-03-15 73 views
5

我在端口3100上运行Express.js(v 2.5.8)(节点v0.6.12)服务器。它由Nginx前端实现,它将http和https请求同时代理为端口3100.通过https在高速/节点上强制请求

我想通过https强制某些URL。下面是一个例子(应用程序是我的Express服务器):

app.get('/applyNow', ensureSec, secure.showApplication); 

ensureSec的是,我试图用它来检查,如果连接是通过SSL功能:

function ensureSec(req, res, next) { 
    if (req.session.ssl == true) { 
     return next(); 
    } else { 
     req.session.ssl = true; 
     res.redirect('https://' + url.parse(req.headers.referer).host + 
     url.parse(req.url).pathname); 
    } 
} 

重定向的作品,但节点(在它超时后)抛出一个错误,说'不能GET/applyNow

什么是重定向到ssl的正确方法?

回答

6

据我所知,您正在使用nginx协商SSL并将http和https请求代理到您的Express应用程序。如果可能的话,我会选择在nginx中解决这个问题,但是如果nginx无法知道哪些路径应该受到保护(即只能通过https访问)或者您想在其他原因的快速应用程序中执行此操作,以下是一些信息:

您应该从nginx获得X-Forwarded-Proto,仅当原协议为https时才设置为https。这里是你如何做到这一点的nginx:

proxy_set_header X-Forwarded-Proto https; 

我也转发Host头:

proxy_set_header Host $http_host; 

在您的明确程序,检查是否存在,或重定向到页眉和请求的主机路(快车解析,为req.path,所以你不必):

function ensureSec(req, res, next) { 
    if (req.headers['x-forwarded-proto'] == 'https') { 
     return next(); 
    } else { 
     res.redirect('https://' + req.headers.host + req.path); 
    } 
} 
+0

这看起来对我来说是正确的解决方案。谢谢! – 2012-03-15 22:01:10

+0

X-Forwarded-Proto标题确实是一个隐藏的宝石。修正它,谢谢。 – 2015-04-12 07:45:14

0

您需要2个不同的快递app对象才能做到这一点。 Express服务器的每个实例一次只能正确监听一个协议。这可以全部在一个node.js进程中,但需要2个不同配置的快速服务器app实例,一个用于http,另一个用于https。见我的答案为例:

How to force SSL/https in Express.js

参见:Automatic HTTPS connection/redirect with node.js/express

另请注意,您不应指定req.session.ssl。将它设置为true并不奇妙地使得客户端与TLS而不是明文HTTP相连接。这是一个只读属性。分配它没有效果。

您还应该注意,您不能在单个端口上运行http和https。这就是为什么HTTP使用80和HTTPS使用443

当你拿到Cannot GET /applyNow错误,这意味着您的明确路线从来不匹配的请求路径,因此您ensureSec中间件从来没有叫。

+0

我正在使用Nginx。 Nginx可以处理http和https连接,所以我可以从我的应用中卸载它。我只需要强制一些路径来运行ssl。 – 2012-03-15 13:26:59

+0

同样,您需要2个不同的端口和2个不同的快速应用程序实例。真。这可以都是一个node.js进程,你可以强制一些http路径重定向到https,但是你不能在同一个端口上同时运行两个完全不同的协议,例如http和https。这不是node.js的限制,它是协议设计的方式。 – 2012-03-15 13:32:08

+0

Peter,据我了解的问题,Rob在前面有一个nginx服务器,将请求代理到一个node.js服务器。所以,对于快速应用程序,所有请求都是http。但是有些路径,Rob不希望快速服务器处理,除非它是https请求(对nginx)。我建议用nginx来强制执行,这看起来简单得多。另外,我的理解是,Rob使用'req.session.ssl'来跟踪通过https连接的客户端,这看起来很片面(你需要在正确的情况下重置)。 – 2012-03-15 17:01:59

0

您可以在您的nginx服务器上配置ssl端口,并像对其他请求一样配置对node.js的代理请求。

http://nginx.org/en/docs/http/configuring_https_servers.html

无需更换的node.js应用程序。只需在nginx上配置443端口,并将证书和代理请求发送到node.js应用程序。

+0

谢谢。我已经这样做了。我只是想保护某些路径。我想在节点应用程序中而不是在nginx中这样做。这样做使部署更容易。 – 2012-03-15 22:00:22

0

要添加到Peter Lyons所说的内容,明确规定您只能在一个端口上运行一台服务器。如果你尝试在一个端口上运行两个http服务器,它会抛出一个EADDRINUSE错误。

+0

是的,谢谢。 – 2012-03-15 22:00:44

0

当你在前端使用Nginx的,实现这一目标的最清洁,最简单的方法就是(重写)的HTTP URL中的Nginx转发到HTTPS,而不是试图重定向在Express中。

server { 
    listen 12.34.56.78:80; 
    server_name yourserver.com; 

    location/{ 
     rewrite^https://$server_name$request_uri permanent; 
    } 
} 

您可以使用此行改写:

rewrite^https://ducklington.org$request_uri permanent; 

刚刚成立了自己的位置,以配合您需要转发到https航线或规则,这可以如下完成。

0

app.enable('trust proxy');

“在反向代理(如Varnish或Nginx)后面使用Express很简单,但它需要配置。通过通过app.enable('trust proxy')启用”trust proxy“设置,Express将知道它是坐在代理后面,并且X-Forwarded- *标头字段可能是可信的,否则可能很容易被欺骗。“

Express behind proxies doco