自定义 Reactor Netty 主机名验证器

Pyv*_*ves 5 java ssl netty reactor-netty

我需要查询证书/DNS 名称不匹配的第三方 API。证书中指定的主机名的最左侧标签事先未知(即CN=some-random-hash.example.com),因此我想使用自定义主机名验证器配置 HTTP 客户端。

当使用通过 获取的默认Reactor NettyHttpClient.create()客户端时,HostnameChecker类会失败证书验证并导致抛出异常:

java.security.cert.CertificateException: No subject alternative DNS name matching XXX found.
    at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:214)
    at sun.security.util.HostnameChecker.match(HostnameChecker.java:96)
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1626)
    ... 30 more
Run Code Online (Sandbox Code Playgroud)

这个相关答案建议按如下方式实现 SNIMatcher:

HttpClient.create()
        .secure(sslContextSpec -> sslContextSpec
                .sslContext(sslContext)
                .handlerConfigurator((handler) -> {
                    SSLEngine engine = handler.engine();
                    SSLParameters params = new SSLParameters();
                    List<SNIMatcher> matchers = new LinkedList<>();
                    SNIMatcher matcher = new SNIMatcher(0) {
                        @Override
                        public boolean matches(SNIServerName serverName) {
                            return true;
                        }
                    };
                    matchers.add(matcher);
                    params.setSNIMatchers(matchers);
                    engine.setSSLParameters(params);
                }));
Run Code Online (Sandbox Code Playgroud)

然而,根据setSNIMatchers 的 Javadocs

此方法仅对在服务器模式下运行的 SSLSocket 或 SSLEngine 有用。

因此,匹配器被忽略,更糟糕的是,上面的代码创建了一个空集SSLParameters,这似乎完全禁用了 SSL 验证。

如何使用Reactor Netty正确实现自定义主机名验证器?

请注意,当使用Apache HTTPClient库时,可以通过以下方式轻松实现:

HttpClients.custom().setSSLHostnameVerifier((hostname, session) -> ...).build();
Run Code Online (Sandbox Code Playgroud)