在ssl验证之前,如何使Node.js / Express.js拒绝基于vhost的连接

时间:2011-12-28 06:30:31

标签: node.js ssl express

我的设置是这样的:

[Apache running on port 80]
http://domain1/  --->   https://domain1/   (redirect using apache)
http://domain2/  --->   Hosted on apache.

[Nodejs running on port 443]
https://domain1/ --->   App on Express.js/Node.js

我现在想要的是,任何对https://domain2/的请求都应该被拒绝连接。

我的ssl证书仅对domain1有效。所以,我做不到这样的事情:

var vhostController = express.createServer({key:privateKey,cert:certificate});
vhostController.use(express.vhost('domain1',mainApp));
vhostController.use(express.vhost('domain2',function(req, res) {res.end();}));
vhostController.listen(443);

上面的代码适用于http,但不适用于https,因为它会在传递给处理返回内容的函数之前尝试验证服务器证书。

所以,是否有一些方法可以在证书错误之前检查请求是针对domain2,还是拒绝/关闭连接

3 个答案:

答案 0 :(得分:3)

在大多数情况下,没有。在发送 HTTP请求之前发生SSL握手(实际上HTTP请求是通过已建立的SSL通道发送的)。 TLS 1.0协议指定了特殊的TLS扩展,它允许客户端告诉服务器,证明哪个主机要呈现。不幸的是,并非所有(我会说很少)客户都支持此扩展,因此您的问题没有通用解决方案。

答案 1 :(得分:1)

这个问题有两个解决方案:

  1. 使用不同的IP:无处不在。
  2. 使用SNI:不需要不同的IP,但不适用于所有客户端(https://sni.velox.ch/处的更多信息)。
  3. 使用不同的IP:

    我最终使用了这种方法。示例代码:

    var app = express.createServer({key:privateKey,cert:certificate});
    // setup app..
    app.listen(443,IP1);
    

    我在端口443上没有在IP2上运行任何东西。因此,任何与IP2的连接都被拒绝。

    使用SNI:

    如果有人想使用SNI,可以在此处找到有关将其与nodejs一起使用的详细信息:

    http://nodejs.org/docs/latest/api/tls.html#event_secureConnection_

    在tls服务器的secureConnection事件中,传递一个cleartextStream变量,其中,如果客户端支持SNI,cleartextStream.servername将提供客户端所需的服务器域。可以在这里查看,并采取适当的措施。

答案 2 :(得分:0)

一种优雅的方法是创建一个中间件函数,如下所示:

function kill_it(res) {
  res.end(); // empty response
}

module.exports = function denyVhost(vhostArray) {
  return function(req, res, next) {
    var host;
    if (req.headers.host) {
      host = req.headers.host.split(':')[0];
      if (vhostArray.indexOf(host) > -1) {
        next(); // the host is found
      } else {
        kill_it(res);
      }
    } else {
      // the host isn't found in the request headers
      kill_it(res);
    }
  }
};

然后在您的快速配置中,您可以像这样使用它:

deny_by_vhost = require('./example_above');

app.configure(function() {
  ...
  app.use(deny_by_vhost(["example.com", "foo.example.com"]));
  ...
});