使用HTTPS和HTTP协议在Express(node.js)中的应用

11

我正在使用 node.js 上的 express (3.0) 框架来路由我的应用程序。

我的大部分应用程序使用 http 协议,但有一个特定的路由我想只通过 https 来提供服务。这是我 API 的一部分,负责注册和验证用户。

例如:

app.get('/connect', function(req, res){
 // Must be on HTTPS, if not redirect to HTTPS
});

app.post('/connect', function(req, res){
  // Must be on HTTPS
});

app.get('/', function(req, res){
 // Must be on HTTP
});

app.get('/build', function(req, res){
 // Must be on HTTP
});

如何在同一个应用程序中同时使用两者?我很难找到任何实际示例。

3个回答

11

只需将你的app(实际上是一个请求处理函数)传递给httphttpscreateServer函数即可。

var express = require('express')
    , http = require('http')
    , https = require('https')
    , app = express();

http.createServer(app);
https.createServer({ ... }, app);

HTTP和HTTPS请求都通过同一个Express应用程序进行路由。在路由处理程序中,要检查请求是否通过https进行,请使用req.secure

app.get('/route', function(req, res) {
    if (req.secure) {
        ...
    } else {
        res.redirect(301, 'https://example.com/route');
    }
});

顺便提一下,现代的智慧认为混合http/https网站是不安全的。你可以通过要求用户通过SSL登录来保护用户的密码,但然后在后续请求中切换回http协议会使攻击者轻而易举地窃取用户的登录cookie。

考虑让所有已登录用户的请求都通过SSL进行。


在这种情况下,如果您需要为安全和非安全请求使用不同的中间件堆栈,该如何处理?例如,对于非安全请求,我不需要会话管理开销,但对于安全请求,我需要。 - Chandu
谢谢,这非常有用。唯一阻止我全面使用HTTPS的是开销问题。这是一个操作密集型的Web应用程序,需要大量的API调用,这样的东西会变得非常明显。我认为,如果用户使用了此类软件危害了自己的系统,那么我不需要为其进行保护。 - George Reith
@GeorgeReith:你实际上测试过开销吗?在现代系统上,SSL的开销占CPU的<1%。事实上,通过像SPDY这样的优化,您可能会发现SSL安全连接实际上比普通HTTP表现更好。我愿意打赌,在现实中,您将无法注意到任何性能差异。此外,会话劫持(窃取登录cookie)是一种被动网络攻击,与受损的用户机器无关。(这正是Facebook现在全部使用HTTPS的原因。)在2013年,没有理由不使用所有SSL(和HSTS)。 - josh3736
@josh3736 不好意思,我看的是关于 SSL 的旧信息。我会先使用两者并进行基准测试,如果 SSL 版本可接受,我将同时使用它。感谢您提供的信息,让我有很多值得思考的地方。 - George Reith
@GeorgeReith - 你是否进行过基准测试,看看完全使用HTTPS和混合/匹配两者之间的性能差异?我现在也处于同样的情况,很想知道你发现了什么! - thisissami
旧帖。但对于任何其他读者来说,这比开销问题更重要。使用HTTPS进行身份验证,然后使用HTTP进行所有其他数据传输就像建立一个门卫但不费心修建围墙。大门是锁着的,但你可以绕过它并拿走你想要的东西。你唯一保护的是你想要保护的数据的密码。但数据仍然在公开的情况下。这使得你的实现无效,并给你一种虚假的安全感。不要这样做。 - Bacon Brad

1
const express = require('express');
const app = express();
const fs = require('fs');
const options = {
    key:fs.readFileSync('./ssl/privkey.pem'),
    cert:fs.readFileSync('./ssl/allchange.pem')
};
const https = require('https').createServer(options,app);
const http = require('http').createServer(app);
app.get('/',(req,res) => {
    (req.protocol == 'http') ? res.redirect('https://www.pkred.com/') : // code
        // More code
        // End code ;
}
app.get('/:id',(req,res) => {
    (req.protocol == 'http') ? res.redirect(`https://www.pkred.com/${req.params.id}`) : // code
        // More code
        // End code ;
}
http.listen(8080,() => console.log('PORT :: 8080'));
https.listen(4433,() => console.log('PORT :: 4433'));

1
尝试这种方法。创建两个express请求处理程序(app_http和app_https)。
在创建http服务器时将app_http作为请求处理程序传递(http.createServer(app_http))。
在创建https服务器时将app_https作为请求处理程序传递(https.createServer(options,app_https))。
var express = require('express'),
    http = require('http'),
    https = require('https');

var app_http = express(); // this one to handle http request

var app_https = express(); // this to handle httpS requests.


app_https.get('/connect', function(req, res){
 // Must be on HTTPS, if not redirect to HTTPS
});

app_https.post('/connect', function(req, res){
  // Must be on HTTPS
});

app_http.get('/', function(req, res){
 // Must be on HTTP
});

app_http.get('/build', function(req, res){
 // Must be on HTTP
});

    //call here http.createServer &  https.createServer with needed details.

谢谢,但我有很多中间件,我真的需要两次指定所有中间件才能侦听处理TLS请求吗? - George Reith
是的,我们需要为它们中的每个加载中间件。为了简化任务,我会这样做:编写一个以应用程序为参数并加载中间件的实用程序函数loadMiddleware(app){app.use(),....}。如果您有这样的功能,则只需进行两个调用,一个使用app_http,另一个使用app_https。希望这可以帮助您。 - Chandu
如果您创建了两个Express请求处理程序,我建议的答案是,您需要为每个处理程序加载中间件。但是,如果您选择使用相同的应用程序并检查请求是否在SSL上,则只需要一次。 - Chandu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接