主机名/ IP不匹配证书的备用名(Hostname / IP doesn't match c

2019-07-17 16:43发布

我试图创建一个使用Node.js的0.8.8使用自签名证书的TLS服务器/客户端安装。

基本服务器代码看起来像

var tlsServer = tls.createServer({
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem')
}, function (connection) {
  // [...]
});
tlsServer.listen(3000);

现在,当我尝试连接到该服务器我用下面的代码:

var connection = tls.connect({
  host: '192.168.178.31',
  port: 3000,

  rejectUnauthorized: true,
  ca: [ fs.readFileSync('server-cert.pem') ]
}, function () {
  console.log(connection.authorized);
  console.log(connection.authorizationError);
  console.log(connection.getPeerCertificate());
});

如果我删除线

ca: [ fs.readFileSync('server-cert.pem') ]

从客户端代码,Node.js的抛出一个错误告诉我DEPTH_ZERO_SELF_SIGNED_CERT 。 据我了解,这是由于这样的事实,这是一个自签名的证书并没有谁相信这个证书没有对方。

如果我删除

rejectUnauthorized: true,

还有,该错误消失-但connection.authorized等于false这实际上意味着我的连接未加密。 总之,使用getPeerCertificate()我可以访问服务器发送的证书。 当我想强制加密连接,我知道我可以不删除此行。

现在我读,我可以使用ca属性来指定,我想Node.js的信任任何CA。 在该TLS模块的文件意味着,这足以服务器证书添加到ca数组,然后一切都应该罚款。

如果我这样做,这个错误没有了,但我得到一个新问题:

Hostname/IP doesn't match certificate's altnames

对我来说,这意味着CA现在基本可信的,因此,现在没事,但该证书的另一台主机比我使用的正确性。

我使用创建的证书

$ openssl genrsa -out server-key.pem 2048
$ openssl req -new -key server-key.pem -out server-csr.pem
$ openssl x509 -req -in server-csr.pem -signkey server-key.pem -out server-cert.pem

如文档暗示。 在创建CSR我问了几个常规问题,如国家,州,......和通用名(CN)。 当你在一个SSL证书“在网络上”告诉你没有提供您的姓名CN,但该主机名,你想使用。

而这可能是在那里我会失败。

我试过了

  • localhost
  • 192.168.178.31
  • eisbaer
  • eisbaer.fritz.box

其中最后两个是当地的名字和我的机器的完全合格的本地名称。

任何想法,我做错了什么?

Answer 1:

最近有一个除了node.js的它允许覆盖主机名检查使用自定义功能。 它被添加到v0.11.14,将在一个稳定版本(0.12)可用。 现在,你可以这样做:

var options = {
  host: '192.168.178.31',
  port: 3000,
  ca: [ fs.readFileSync('server-cert.pem') ],
  checkServerIdentity: function (host, cert) {
    return undefined;
  }
};
options.agent = new https.Agent(options);
var req = https.request(options, function (res) {
  //...
});

现在,这将接受任何服务器的身份,但仍加密连接,并验证密钥。

请注意 ,在以前的版本(如v0.11.14 ),该checkServerIdentity是返回一个boolean指示服务器的有效性。 已更改(之前v4.3.1 )的函数return荷兰国际集团(不throw荷兰国际集团)的错误,如果有问题, undefined ,如果有它是有效的。



Answer 2:

在tls.js,行112-141 ,你可以看到,如果在调用时所使用的主机名connect是一个IP地址,证书的CN被忽略,并且正在使用只的SAN。

正如我的证书不使用的SAN,验证失败。



Answer 3:

如果您使用的是主机名进行连接,主机名称将针对DNS类型的主题备用名称进行检查,如果有的话,然后在主题的专有名称依傍CN否则。

如果您使用的IP地址进行连接时,IP地址将被打击的IP地址类型的SAN中,检查没有回落的CN。

这至少是实现兼容与HTTP超过TLS规范(即HTTPS)做的。 有些浏览器是多一点宽容。

这也正是同样的问题在这个答案在Java中 ,这也给通过OpenSSL的把自定义的SAN(见的方法这个文件太 )。

一般来说,除非它是一个测试CA,这是相当难以管理依赖于IP地址的证书。 与主机名连接好。



Answer 4:

米塔尔有一个错误的假设,即checkServerIdentity应在成功返回“真”,但实际上它应该在成功返回“未定义”。 任何其他值被视为错误的描述。

所以,这样的代码是正确的:

var options = {
  host: '192.168.178.31',
  port: 3000,
  ca: [ fs.readFileSync('server-cert.pem') ],
  checkServerIdentity: function (host, cert) {
    // It can be useful to resolve both parts to IP or to Hostname (with some synchronous resolver (I wander why they did not add done() callback as the third parameter)).
    // Be carefull with SNI (when many names are bound to the same IP).
    if (host != cert.subject.CN)
      return 'Incorrect server identity';// Return error in case of failed checking.
      // Return undefined value in case of successful checking.
      // I.e. you could use empty function body to accept all CN's.
  }
};
options.agent = new https.Agent(options);
var req = https.request(options, function (res) {
  //...
});

我想只是为了在米塔尔的答案编辑,但编辑被拒绝,所以我创建了一个分开的答案。



Answer 5:

你在做什么错误使用IP地址而不是一个域名是。 创建一个域名,并把它贴在DNS服务器(或只是在hosts文件),创建一个域名作为通用名称自签名证书,并连接到域名,而不是IP地址。



文章来源: Hostname / IP doesn't match certificate's altname