为什么 requestjs 拒绝适用于 Firefox 的自签名 SSL 证书?
Why does requestjs reject a self-signed SSL certificate that works with Firefox?
情况是这样的。我创建了一个自签名 CA 证书,并用它来签署第二个用于 https 的证书。 Web 服务器是 nginx,对 expressjs 应用程序执行 SSL 终止和反向代理。为了验证信任链是否正确,我在 Firefox 中安装了 CA,并且能够通过 https 访问该网站而没有警告,正如预期的那样。此外,我可以使用 openssl x509 -in server.crt -text -noout
检查服务器的证书,并且我看到了预期的颁发者,特别是主题的预期通用名称。 (注意:此处使用的通用名称是IP地址,以免造成麻烦。)
但是,当我尝试使用 requestjs 通过 nodejs 脚本访问服务器时,事情并没有那么顺利。在脚本中,使用如下代码加载 CA 证书:
request.get({url: theUrl, ca: fs.readFileSync("./ca.crt")}, ...
但是我得到了这个错误(为了便于阅读,换行,原来是一行):
Contacting doorman failed: Error: Hostname/IP doesn't match certificate's altnames:
"IP: <redacted> is not in the cert's list: "
特别可疑的是,好像在说"cert's list"是空的。在其他答案中建议在选项中使用 rejectUnauthorized: false
,但对于此应用程序来说这不是一个很好的选择,因为我想要进行身份验证。
如何让requestjs/nodejs信任这个证书?
服务器证书的内容,由 openssl x509 -text
报告
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 3 (0x3)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=State, L=City, O=Company, CN=www.company.com
Validity
Not Before: Dec 7 17:19:51 2015 GMT
Not After : Oct 14 17:19:51 2025 GMT
Subject: C=US, ST=State, L=City, O=Company, CN=1.2.3.4/emailAddress=webmaster@company.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
...
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
...
以及用于生成该证书的配置文件:
[ req ]
default_bits = 4096
prompt = no
encrypt_key = no
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
countryName = "US"
stateOrProvinceName = "State"
localityName = "City"
organizationName = "Company"
commonName = "1.2.3.4"
emailAddress = "webmaster@company.com"
[ v3_req ]
subjectAltName = IP:1.2.3.4
Hostname/IP doesn't match certificate's altnames:
我的猜测是您的证书包含在 URL 中仅用作主题 (CN) 而不是主题备用名称 (SAN) 的正确主机名,但它包含其他名称作为 SAN。该标准非常明确,如果给出了任何主题替代 DNS 名称,则不应检查 CN,但大多数浏览器无论如何都会检查 CN(我认为 Safari 更严格)。但是 node.js 实施了严格的行为,因此会失败。
如果我的猜测是正确的(没有证书很难看清),那么必须通过创建正确的证书来解决问题。另一种可能性是您在浏览器和 nodejs 中使用略有不同的 URL(例如有无 www
前缀)。
编辑:在看到您实际使用的证书后....
您有一个IP地址在CN的证书。虽然这也被大多数浏览器支持,但这是不对的。 IP 地址必须作为 ipadress SAN 条目而不是 CN 给出。 Nodejs 只希望它在那里,我认为 Safari 也那么严格。请注意,对于 IE,您必须将其放入 CN 或作为 dnsname SAN 条目,因为它们在这种情况下也喜欢违反标准。因此为了安全起见,将其作为 ipaddress、dnsname,也可能作为 CN。
情况是这样的。我创建了一个自签名 CA 证书,并用它来签署第二个用于 https 的证书。 Web 服务器是 nginx,对 expressjs 应用程序执行 SSL 终止和反向代理。为了验证信任链是否正确,我在 Firefox 中安装了 CA,并且能够通过 https 访问该网站而没有警告,正如预期的那样。此外,我可以使用 openssl x509 -in server.crt -text -noout
检查服务器的证书,并且我看到了预期的颁发者,特别是主题的预期通用名称。 (注意:此处使用的通用名称是IP地址,以免造成麻烦。)
但是,当我尝试使用 requestjs 通过 nodejs 脚本访问服务器时,事情并没有那么顺利。在脚本中,使用如下代码加载 CA 证书:
request.get({url: theUrl, ca: fs.readFileSync("./ca.crt")}, ...
但是我得到了这个错误(为了便于阅读,换行,原来是一行):
Contacting doorman failed: Error: Hostname/IP doesn't match certificate's altnames:
"IP: <redacted> is not in the cert's list: "
特别可疑的是,好像在说"cert's list"是空的。在其他答案中建议在选项中使用 rejectUnauthorized: false
,但对于此应用程序来说这不是一个很好的选择,因为我想要进行身份验证。
如何让requestjs/nodejs信任这个证书?
服务器证书的内容,由 openssl x509 -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 3 (0x3)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=State, L=City, O=Company, CN=www.company.com
Validity
Not Before: Dec 7 17:19:51 2015 GMT
Not After : Oct 14 17:19:51 2025 GMT
Subject: C=US, ST=State, L=City, O=Company, CN=1.2.3.4/emailAddress=webmaster@company.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
...
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
...
以及用于生成该证书的配置文件:
[ req ]
default_bits = 4096
prompt = no
encrypt_key = no
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
countryName = "US"
stateOrProvinceName = "State"
localityName = "City"
organizationName = "Company"
commonName = "1.2.3.4"
emailAddress = "webmaster@company.com"
[ v3_req ]
subjectAltName = IP:1.2.3.4
Hostname/IP doesn't match certificate's altnames:
我的猜测是您的证书包含在 URL 中仅用作主题 (CN) 而不是主题备用名称 (SAN) 的正确主机名,但它包含其他名称作为 SAN。该标准非常明确,如果给出了任何主题替代 DNS 名称,则不应检查 CN,但大多数浏览器无论如何都会检查 CN(我认为 Safari 更严格)。但是 node.js 实施了严格的行为,因此会失败。
如果我的猜测是正确的(没有证书很难看清),那么必须通过创建正确的证书来解决问题。另一种可能性是您在浏览器和 nodejs 中使用略有不同的 URL(例如有无 www
前缀)。
编辑:在看到您实际使用的证书后....
您有一个IP地址在CN的证书。虽然这也被大多数浏览器支持,但这是不对的。 IP 地址必须作为 ipadress SAN 条目而不是 CN 给出。 Nodejs 只希望它在那里,我认为 Safari 也那么严格。请注意,对于 IE,您必须将其放入 CN 或作为 dnsname SAN 条目,因为它们在这种情况下也喜欢违反标准。因此为了安全起见,将其作为 ipaddress、dnsname,也可能作为 CN。