2012-03-15 78 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