Reputation: 455
I'm using a HttpURLConnection
in order create a POST request (for fetching a token at some OAuth2 token endpoint). The token endpoint uses HTTPS. I wonder how the hostname verification with regards to HTTPS works. The default hostname verifier of HttpsURLConnection
seems to be the following [1]:
/**
* HostnameVerifier provides a callback mechanism so that
* implementers of this interface can supply a policy for
* handling the case where the host to connect to and
* the server name from the certificate mismatch.
*
* The default implementation will deny such connections.
*/
private static HostnameVerifier defaultHostnameVerifier =
new HostnameVerifier() {
public boolean verify(String urlHostname, String certHostname) {
return false;
}
};
I expected my POST request to fail as this verifier always returns false
. This is not the case. The comment already states that there is some kind of callback mechanism. What I do not know is: Does the defaultHostnameVerifier
verify the hostname of the connection and the certificate or is it rather a dummy implementation?
My current coding looks like the following piece:
private HttpURLConnection openConnection(String url) throws IOException {
URL urly = new URL(url);
final HttpURLConnection con;
Proxy proxy = getProxy();
if (proxy == null) {
con = (HttpURLConnection) urly.openConnection();
} else {
con = (HttpURLConnection) urly.openConnection(proxy);
}
if (con instanceof HttpsURLConnection) {
HostnameVerifier verifier = ((HttpsURLConnection) con).getHostnameVerifier(); // there is a default set
System.out.println(verifier.getClass().getName());
}
return con;
}
I've found some explanation with regards to the AsyncHttpClient
[2]. As I do not use it at this point of time am I safe going with the default implementation?
Upvotes: 2
Views: 4023
Reputation: 38821
As the comments at the top say, that class is no longer used; it was the abstract user-visible class that is now replaced by javax.net.HttpsURLConnection which you will observe has the same code. But the implementation class for https URL is sun.net.www.protocol.https.HttpsURLConnectionImpl which just wraps (delegates to) sun.net.www.protocol.https.DelegateHttpsURLConnection which subclasses sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection which to make the actual connection uses sun.net.www.protocol.HttpsClient and in particular .afterConnect(). As background, in earlier versions of Java SSLSocket
did not do hostname verification, so the implementation of HttpsURLConnection had to add it. In Java 7 up, SSLSocket
does support 'endpoint identification', so when afterConnect() recognizes that the hostnameVerifier on this URLconnection was the default one, it turns off needToCheckSpoofing
and sets the SSLSocket
to do endpoint identification.
javax.net.ssl.SSLSocket is similarly an abstract class that is actually implemented by sun.security.ssl.SSLSocketImpl and several dozen related classes including sun.security.ssl.ClientHandshaker.serverCertificate() which calls the configurable trustmanager which by default is sun.security.ssl.X509TrustManagerImpl which in checkTrusted() since endpoint identification was requested calls checkIdentity() which calls sun.security.util.HostnameChecker with TYPE_TLS (actually meaning HTTPS RFC 2818), and that does the actual checking.
Glad you asked?
PS: the analysis on that webpage, that HttpsURLConnection.DefaultHostnameVerifier is called only for mismatch, is quite wrong. As above it is bypassed and never called by the actual implementation.
Also I assume you realize java 7 has not been supported for years unless you pay. Although this area hasn't changed that I know of in more recent versions. Java 11 does add a new java.net.http.HttpClient which functionally supersedes [Http,Https]URLConnection.
Upvotes: 5