Node.js 主机名/IP 与证书的替代名称不匹配
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14262986/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Node.js Hostname/IP doesn't match certificate's altnames
提问by mr0re1
I have code:
我有代码:
var r = require('request');
r({
method: 'POST',
url: 'https://api.dropbox.com'},
function() { console.log(arguments) } )
When I run it on desktop with Node 0.9.4, I get this in the console:
当我使用 Node 0.9.4 在桌面上运行它时,我在控制台中得到了这个:
{ '0': [Error: Hostname/IP doesn't match certificate's altnames] }
When I run it on Netbook with Node 0.6.12, it all works without error (302 response - I think its right).
当我在使用 Node 0.6.12 的上网本上运行它时,一切正常(302 响应 - 我认为它是正确的)。
In question Node.js hostname/IP doesnt match certificates altnames, Rojuinex write: "Yeah, browser issue... sorry". What does "browser issue" mean?
在Node.js 主机名/IP 与证书 altnames 不匹配的问题中,Rojuinex 写道:“是的,浏览器问题......抱歉”。“浏览器问题”是什么意思?
UPD. This problem was resolved after roll back on Node v0.8
更新。此问题在 Node v0.8 回滚后解决
回答by natevw
Since 0.9.2 (including 0.10.x) node.js now validates certificates by default. This is why you could see it become more strict when you upgrade past node.js 0.8. (HT: https://github.com/mscdex/node-imap/issues/181#issuecomment-14781480)
从 0.9.2(包括 0.10.x)开始,node.js 现在默认验证证书。这就是为什么当你升级超过 node.js 0.8 时,你会看到它变得更加严格。(HT:https: //github.com/mscdex/node-imap/issues/181#issuecomment-14781480)
You can avoid this with the {rejectUnauthorized:false}option, however this has serious security implications. Anything you send to the peer will still be encrypted, but it becomes mucheasier to mount a man-in-the-middle attack, i.e. your data will be encrypted to the peer but the peer itself is not the server you think it is!
您可以使用该{rejectUnauthorized:false}选项来避免这种情况,但这会带来严重的安全隐患。您发送给对等方的任何内容仍将被加密,但是发起中间人攻击变得更加容易,即您的数据将被加密给对等方,但对等方本身并不是您认为的服务器!
It would be better to first diagnose why the certificate is not authorizing and see if that could be fixed instead.
最好先诊断证书未授权的原因,然后查看是否可以修复。
回答by Jason Walton
A slightly updated answer (since I ran into this problem in different circumstances.)
稍微更新的答案(因为我在不同情况下遇到了这个问题。)
When you connect to a server using SSL, the first thing the server does is present a certificate which says "I am api.dropbox.com." The certificate has a "subject" and the subject has a "CN" (short for "common name".) The certificate may also have one or more "subjectAltNames". When node.js connects to a server, node.js fetches this certificate, and then verifies that the domain name it thinks it's connecting to (api.dropbox.com) matches either the subject's CN or one of the altnames. Note that, in node 0.10.x, if you connect using an IP, the IP address has to be in the altnames - node.js will not try to verify the IP against the CN.
当您使用 SSL 连接到服务器时,服务器所做的第一件事就是提供一个证书,上面写着“我是 api.dropbox.com”。证书有一个“subject”,而subject 有一个“CN”(“common name”的缩写)。证书也可能有一个或多个“subjectAltNames”。当 node.js 连接到服务器时,node.js 获取此证书,然后验证它认为它连接到的域名 (api.dropbox.com) 是否与主题的 CN 或替代名称之一匹配。请注意,在节点 0.10.x 中,如果您使用 IP 连接,则 IP 地址必须在替代名称中 - node.js 不会尝试针对 CN 验证 IP。
Setting the rejectUnauthorizedflag to false will get around this check, but first of all if the server is giving you different credentials than you are expecting, something fishy is going on, and second this will also bypass other checks - it's not a good idea if you're connecting over the Internet.
将rejectUnauthorized标志设置为 false 将绕过此检查,但首先,如果服务器为您提供的凭据与您预期的不同,则会发生一些可疑的事情,其次这也会绕过其他检查 - 如果您这样做,这不是一个好主意正在通过 Internet 连接。
If you are using node >= 0.11.x, you can also specify a checkServerIdentity: function(host, cert)function to the tls module, which should return undefinedif you want to allow the connection and throw an exception otherwise (although I don't know if requestwill proxy this flag through to tls for you.) It can be handy to declare such a function and console.log(host, cert);to figure out what the heck is going on.
如果你使用 node >= 0.11.x,你也可以指定一个checkServerIdentity: function(host, cert)函数给 tls 模块,undefined如果你想允许连接它应该返回,否则抛出异常(虽然我不知道是否request会通过代理这个标志tls 给你。)声明这样一个函数并console.log(host, cert);弄清楚到底发生了什么会很方便。
回答by Black
In case you are using http-proxypackage this happens when your server is HTTP (for example localhost) and target is HTTPS. To fix this issue set changeOrigin to true.
如果您使用http-proxy包,当您的服务器是 HTTP(例如 localhost)并且目标是 HTTPS 时会发生这种情况。要解决此问题,请将 changeOrigin 设置为 true。
const proxy = httpProxy.createProxyServer();
proxy.web(req, res, {
changeOrigin: true,
target: https://example.com:3000,
});
In case your server is HTTPS and target one is HTTPS as well, you should include SSL certificate
如果您的服务器是 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);
回答by Geoffrey Burdett
I know this is old, BUT for anyone else looking:
我知道这很旧,但对于其他人来说:
Remove https:// from the hostname and add port 443 instead.
从主机名中删除 https:// 并改为添加端口 443。
{
method: 'POST',
hostname: 'api.dropbox.com',
port: 443
}
回答by Etienne
I had the same issue using the request module to proxy POST request from somewhere else and it was because I left the host property in the header (I was copying the header from the original request).
我在使用请求模块代理来自其他地方的 POST 请求时遇到了同样的问题,这是因为我将主机属性留在了标头中(我从原始请求中复制了标头)。
回答by hrdwdmrbl
The other way to fix this in other circumstances is to use NODE_TLS_REJECT_UNAUTHORIZED=0as an environment variable
在其他情况下解决此问题的另一种方法是NODE_TLS_REJECT_UNAUTHORIZED=0用作环境变量
NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js
NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js
回答by Russ Cam
After verifying that the certificate is issued by a known Certificate Authority (CA), the Subject Alternative Names will be checked, or the Common Name will be checked, to verify that the hostname matches. This is in the checkServerIdentity function. If the certificate has Subject Alternative Names and the hostname is not listed, you'll see the error message described:
在验证证书是由已知的证书颁发机构 (CA) 颁发后,将检查主题备用名称或通用名称,以验证主机名是否匹配。这是在checkServerIdentity 函数中。如果证书具有主题备用名称并且未列出主机名,您将看到描述的错误消息:
Hostname/IP doesn't match certificate's altnames
主机名/IP 与证书的替代名称不匹配
If you have the CA cert that is used to generate the certificate you're using (usually the case when using self-signed certificates), this can be provided with
如果您拥有用于生成您正在使用的证书的 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
});
This will verify that the certificate is issued by the CA provided, but hostname verification will still be performed. Just supplying the CA will be enough if the cert contains the hostname in the Subject Alternative Names. If it doesn't and you also want to skip hostname verification, you can pass a noop function for checkServerIdentity
这将验证证书是否由提供的 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
});
回答by Jeff Pal
We don't have this problem if we are testing our client request with localhostdestination address (hostor hostnameon node.js) and our server common name is CN = localhostin the server cert. But even if we change localhostfor 127.0.0.1or any other IP we'll get error Hostname/IP doesn't match certificate's altnameson node.js or SSL handshake failedon QT.
如果我们使用localhost目标地址(host或hostname在 node.js 上)测试我们的客户端请求并且我们的服务器通用名称CN = localhost在服务器证书中,我们就没有这个问题。但是,即使我们改变localhost的127.0.0.1或任何其他知识产权,我们会得到错误Hostname/IP doesn't match certificate's altnames的node.js的或SSL handshake failed对QT。
I had the same issue about my server certificate on my client request. To solve it on my client node.js app I needed to put a subjectAltNameon my server_extensionwith the following value:
我的客户端请求中的服务器证书也有同样的问题。为了解决它在我的客户端的node.js程序,我需要把subjectAltName我的server_extension有以下值:
[ server_extension ]
.
.
.
subjectAltName = @alt_names_server
[alt_names_server]
IP.1 = x.x.x.x
and then I use -extensionwhen I create and sign the certificate.
然后我-extension在创建和签署证书时使用。
example:
例子:
In my case, I first export the issuer's config file because this file contents the server_extension:
就我而言,我首先导出发行人的配置文件,因为该文件包含以下内容server_extension:
export OPENSSL_CONF=intermed-ca.cnf
so I create and sign my server cert:
所以我创建并签署了我的服务器证书:
openssl ca \
-in server.req.pem \
-out server.cert.pem \
-extensions server_extension \
-startdate `date +%y%m%d000000Z -u -d -2day` \
-enddate `date +%y%m%d000000Z -u -d +2years+1day`
It works fine on clients based on node.js with https requests but it doesn't work with clients based on QT QSsl when we define
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer), unless we useQSslSocket::VerifyNoneit won't work. If we useVerifyNoneit will make our app to don't check the peer certificate so it'll accept any cert. So, to solve it I need to change my server common name on its cert and replace its value for the IP Address where my server is running.
它在基于 node.js 和 https 请求的客户端上运行良好,但在我们定义时它不适用于基于 QT QSsl 的客户端
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer),除非我们使用QSslSocket::VerifyNone它不会工作。如果我们使用VerifyNone它会使我们的应用程序不检查对等证书,因此它将接受任何证书。因此,要解决此问题,我需要更改其证书上的服务器通用名称,并将其值替换为运行服务器的 IP 地址。
for example:
例如:
CN = 127.0.0.1
CN = 127.0.0.1
回答by u4617295
If you are going to trust a sub-domain, for example, aaa.localhost,
Please don't do it like mkcert localhost *.localhost 127.0.0.1, this will not work since some browser doesn't accept wildcard subdomain.
如果您要信任子域,例如 aaa.localhost,请不要这样做mkcert localhost *.localhost 127.0.0.1,这将不起作用,因为某些浏览器不接受通配符子域。
Maybe try mkcert localhost aaa.localhost 127.0.0.1.
也许试试mkcert localhost aaa.localhost 127.0.0.1。

