SSLHandshakeException: hostname in certificate did

2020-07-20 04:43发布

问题:

I am writing a system that must make a multipart post to a server (a third-party program called ARX that is currently running on localhost during the development) that has a self-signed certificate.

I tried to find its certificate, but can only find three different jks files; server.jks, servertrust.jks and serverca.jks.

I have tried to use the System.setProperty("javax.net.ssl.trustStore", "Program Files\\<path>\\jksfile") with each of the jks files. However; when I do, I get the following error: hostname in certificate didn't match: < localhost> != <9200416 arx sa cert>.

I have browsed plenty of similar questions here on stackoverflow to try and get an idea on how to fix this, but I have not been able to resolve my problem.

Any suggestions? All help is very much appreciated.

回答1:

The certificate itself seems trusted, so your javax.net.ssl.trustStore setting worked, but the host name doesn't match.

Host name matching is done according to how the client identifies the host it's trying to access. If it's trying to access https://localhost/, then the certificate must be valid for localhost. If it's trying to access https://something-else.example, then the certificate must be valid for something-else.example, even if localhost and something-else.example are one and the same machine.

The identifier in the certificate should be in a Subject Alternative Name extension or, failing that, in the Common Name (CN) of the Subject Distinguished Name.

Here, it looks like your certificate only has a CN and that this CN is for "9200416 arx sa cert".

In principle, you could address that problem by having that name point to your localhost using your hosts file on your development machine. However, that name contains spaces, so it's not even a valid host name.

You get a couple of options:

  1. Re-generate the certificate for that application, so that it uses a proper host name (and if required, adapt your hosts file). This might just be a mistake when it was set up. Maybe someone just filled in that name with spaces, without realising it would be used like that in the cert (OpenSSL sometimes calls this "Your Name", for example).

  2. A bad option would be to change your application to ignore host name validation. This is a bad option because this leaves your code open to MITM attacks. Of course, this barely matters from localhost to localhost, but that's the kind of code that stays in the code. Because it will prevent an error (that would otherwise be an intended error) from happening, it's likely that removing this from production code will be forgotten. Even in places with good development practices, it's easy to miss. That's a bad option (just to stress this point).

    A slightly better variant for this would be to have a custom host name verifier that checks the name it finds is the name you know to be in the certificate.