HttpsURLConnections Default Hostname Verifier

mon*_*nti 2 java https

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;
            }
        };
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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?

[1] https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/com/sun/net/ssl/HttpsURLConnection.java#L76

[2] https://kevinlocke.name/bits/2012/10/03/ssl-certificate-verification-in-dispatch-and-asynchttpclient/

dav*_*085 5

正如顶部的评论所说,该类不再使用;它是抽象的用户可见类,现在已被javax.net.HttpsURLConnection取代,您将观察到它具有相同的代码。但是https URL的实现类是sun.net.www.protocol.https.HttpsURLConnectionImpl,它只是包装(委托给)sun.net.www.protocol.https.DelegateHttpsURLConnection,它是sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection的子类要进行实际连接,请使用sun.net.www.protocol.HttpsClient,特别是 .afterConnect()。作为背景,在早期版本的Java中SSLSocket没有进行主机名验证,因此HttpsURLConnection的实现必须添加它。在 Java 7 及以上版本中,SSLSocket确实支持“端点识别”,因此当 afterConnect() 识别出此 URLconnection 上的主机名验证器是默认值时,它会关闭needToCheckSpoofing并设置SSLSocket进行端点识别。

javax.net.ssl.SSLSocket类似地是一个抽象类,实际上由sun.security.ssl.SSLSocketImpl和几十个相关类实现,包括sun.security.ssl.ClientHandshaker.serverCertificate(),它调用可配置的 trustmanager,默认情况下是sun.security.ssl.X509TrustManagerImplcheckTrusted()中,因为请求了端点标识,所以调用checkIdentity(),后者使用TYPE_TLS 调用sun.security.util.HostnameChecker(实际上意味着 HTTPS RFC 2818),并执行实际检查。

很高兴你问了?

PS:该网页上的分析认为,仅因不匹配而调用 HttpsURLConnection.DefaultHostnameVerifier,这是完全错误的。如上所述,它被绕过并且从未被实际实现调用。

另外,我假设您意识到 java 7 多年来一直不受支持,除非您付费。尽管据我所知,在最近的版本中这个区域没有改变。Java 11 确实添加了一个新的 java.net.http.HttpClient,它在功能上取代了 [Http,Https]URLConnection。