问题
Here's the situation. I created a self-signed CA certificate, and used it to sign a second certificate for use with https. The web server is nginx doing SSL termination and reverse proxying to an expressjs application. To verify that the chain of trust is correct, I installed the CA in Firefox and was able to access the website over https without warnings, as expected. Further, I can inspect the server's certificate with openssl x509 -in server.crt -text -noout
, and I see both the expected issuer and in particular the expected common name for the subject. (Note: the common name being used here is an IP address, in case that might cause trouble.)
However, when I try to access the server via a nodejs script using requestjs, things don't go so smoothly. In the script, the CA certificate is loaded using code like this:
request.get({url: theUrl, ca: fs.readFileSync("./ca.crt")}, ...
But I get this error (line broken for readability, original is one line):
Contacting doorman failed: Error: Hostname/IP doesn't match certificate's altnames:
"IP: <redacted> is not in the cert's list: "
It's particularly suspicious that it seems to be saying that the "cert's list" is empty. Using rejectUnauthorized: false
in the options has been suggested in other answers, but it isn't a great option for this application because I want to have the identity validation.
How can I make requestjs/nodejs trust this certificate?
Contents of the server certificate, as reported by 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
...
And the config file used to generate that certificate:
[ 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
回答1:
Hostname/IP doesn't match certificate's altnames:
My guess is that your certificate contains the correct hostname used in the URL only as subject (CN) and not as subject alternative name (SAN), but that it contains other names as SAN. The standard is quite clear that if any subject alternative DNS names are given the CN should not be checked, but most browsers check CN anyway (I think Safari is more strict). But node.js implements the strict behavior and will thus fail.
If my guess is right (hard to see without certificate) then the issue has to be fixed by creating a correct certificate. Another possibility is that you use a slightly different URL in browser and nodejs (like with and without www
prefix).
EDIT: after seeing what certificate you actually use....
You have a certificate with an IP address in the CN. While this is also supported by most browsers it is not right. An IP address must be given as ipadress SAN entry and not as CN. Nodejs expects it only there and I think that Safari is also that strict. Note that for IE you have to put it either into CN or as dnsname SAN entry just because they like to behave contrary to the standard in this case too. Thus to be on the safe side put it as ipaddress, dnsname and maybe as CN too.
来源:https://stackoverflow.com/questions/34138384/why-does-requestjs-reject-a-self-signed-ssl-certificate-that-works-with-firefox