Node.js主机名/ IP与证书的altnames不匹配

mr0*_*re1 51 node.js

我有代码:

var r = require('request');
r({
  method: 'POST',
  url: 'https://api.dropbox.com'},
  function() { console.log(arguments)  } )
Run Code Online (Sandbox Code Playgroud)

当我使用Node 0.9.4在桌面上运行它时,我在控制台中得到它:

{ '0': [Error: Hostname/IP doesn't match certificate's altnames] }
Run Code Online (Sandbox Code Playgroud)

当我在Netbook上使用Node 0.6.12运行它时,它都可以正常工作(302响应 - 我认为是正确的).

有问题Node.js主机名/ IP不匹配证书altnames,Rojuinex写道:"是的,浏览器问题......对不起"."浏览器问题"是什么意思?

UPD.在节点v0.8上回滚后,此问题已得到解决

nat*_*evw 65

由于0.9.2(包括0.10.x)node.js现在默认验证证书.这就是为什么当你升级过去node.js 0.8时你会发现它变得更加严格的原因.(HT:https://github.com/mscdex/node-imap/issues/181#issuecomment-14781480)

您可以使用该{rejectUnauthorized:false}选项来避免这种情况,但这会产生严重的安全隐患.您发送给对等方的任何内容仍然会被加密,但是容易安装中间人攻击,即您的数据将被加密到对等方,但对等方本身并不是您认为的服务器!

最好首先诊断证书未授权的原因,看看是否可以修复证书.

  • 与其使用rejectUnauthorized:false并禁用SSL及其好处,不如使用checkServerIdentity: () => undefined来跳过ip检查。 (3认同)

Jas*_*ton 27

稍微更新的答案(因为我在不同情况下遇到了这个问题.)

当您使用SSL连接到服务器时,服务器所做的第一件事就是出现一个证明"我是api.dropbox.com"的证书.证书具有"主题",主题具有"CN"("通用名称"的缩写).证书也可以具有一个或多个"subjectAltNames".当node.js连接到服务器时,node.js获取此证书,然后验证它认为它连接到的域名(api.dropbox.com)是否与主题的CN或其中一个altnames匹配.请注意,在节点0.10.x中,如果使用IP进行连接,则IP地址必须位于altnames中 - node.js不会尝试针对CN验证IP.

rejectUnauthorized标志设置为false将绕过此检查,但首先如果服务器提供的凭据与您预期的不同,可能会出现问题,其次是绕过其他检查 - 如果您不是一个好主意通过互联网连接.

如果您使用的是节点> = 0.11.x,您还可以为checkServerIdentity: function(host, cert)tls模块指定一个函数,undefined如果您想允许连接则返回该函数,否则抛出异常(尽管我不知道是否request会通过代理此标志为你服务.)宣布这样一个功能并console.log(host, cert);弄清楚到底发生了什么是很方便的.


Bla*_*ack 23

如果您使用的是http-proxy软件包,则当您的服务器是HTTP(例如localhost)且目标是HTTPS时会发生这种情况.要解决此问题,请将changeOrigin设置为true.

const proxy = httpProxy.createProxyServer();

proxy.web(req, res, {
  changeOrigin: true,
  target: https://example.com:3000,
});
Run Code Online (Sandbox Code Playgroud)

如果您的服务器是HTTPS,而目标服务器也是HTTPS,则应包括SSL证书

httpProxy.createServer({
  ssl: {
    key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
    cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
  },
  target: 'https://example.com:3000',
  secure: true
}).listen(443);
Run Code Online (Sandbox Code Playgroud)


Geo*_*ett 8

我知道这是旧的,但对于其他任何人看:

从主机名中删除https://并添加端口443.

{
  method: 'POST',
  hostname: 'api.dropbox.com',
  port: 443
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用的是非标准端口,则无法使用。 (3认同)

Rus*_*Cam 8

在验证证书由已知的证书颁发机构 (CA) 颁发后,将检查主题备用名称或通用名称,以验证主机名是否匹配。这是在checkServerIdentity 函数中。如果证书具有主题备用名称并且未列出主机名,您将看到描述的错误消息:

主机名/IP 与证书的替代名称不匹配

如果您拥有用于生成您正在使用的证书的 CA 证书(通常是使用自签名证书时的情况),则可以提供

var r = require('request');

var opts = {
    method: "POST",
    ca: fs.readFileSync("ca.cer")
};

r('https://api.dropbox.com', opts, function (error, response, body) {
    // do something
});
Run Code Online (Sandbox Code Playgroud)

这将验证证书是否由提供的 CA 颁发,但仍将执行主机名验证。如果证书在主题备用名称中包含主机名,只需提供 CA 就足够了。如果没有,并且您还想跳过主机名验证,则可以传递一个 noop 函数checkServerIdentity

var r = require('request');

var opts = {
    method: "POST",
    ca: fs.readFileSync("ca.cer"),
    agentOptions: { checkServerIdentity: function() {} }
};

r('https://api.dropbox.com', opts, function (error, response, body) {
    // do something
});
Run Code Online (Sandbox Code Playgroud)


Eti*_*nne 7

使用request模块从其他地方代理POST请求时,我遇到了同样的问题,这是因为我将host属性留在了标头中(我是从原始请求中复制标头)。


hrd*_*rbl 6

在其他情况下解决此问题的另一种方法是NODE_TLS_REJECT_UNAUTHORIZED=0用作环境变量

NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js

  • 这样做与设置“{rejectUnauthorized:false}”选项相同,并且也存在重大安全问题。 (7认同)