1

这是情况。我创建了一个自签名 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: "

特别可疑的是,它似乎在说“证书列表”是空的。在其他答案中建议使用rejectUnauthorized: falsein the options ,但这对于此应用程序来说不是一个很好的选择,因为我想要进行身份验证。

我怎样才能让 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
4

1 回答 1

3

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

我的猜测是您的证书包含 URL 中使用的正确主机名,仅作为主题 (CN) 而不是主题替代名称 (SAN),但它包含其他名称作为 SAN。标准非常明确,如果给出了任何主题替代 DNS 名称,则不应检查 CN,但大多数浏览器无论如何都会检查 CN(我认为 Safari 更严格)。但是 node.js 实现了严格的行为,因此会失败。

如果我的猜测是正确的(没有证书很难看到),那么必须通过创建正确的证书来解决问题。另一种可能性是您在浏览器和 nodejs 中使用的 URL 略有不同(例如带和不带www前缀)。

编辑:在看到你实际使用的证书之后......

您在 CN 中有一个带有 IP 地址的证书。虽然大多数浏览器也支持这一点,但这是不对的。IP 地址必须作为 ipadress SAN 条目而不是 CN。Nodejs 只希望它在那里,我认为 Safari 也很严格。请注意,对于 IE,您必须将其放入 CN 或作为 dnsname SAN 条目,因为它们也喜欢在这种情况下表现出与标准相反的行为。因此,为了安全起见,请将其设置为 ipaddress、dnsname 和 CN。

于 2015-12-07T16:41:34.703 回答