【问题标题】:Ignore self signed certificates in AsyncClientHttp2Multiplexing忽略 AsyncClientHttp2Multiplexing 中的自签名证书
【发布时间】:2018-07-26 01:00:58
【问题描述】:

我正在尝试使用单个客户端端点创建多个异步 HTTP 连接我已经尝试过Apache site 中给出的多路复用示例

代码sn-p如下,

final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
            .setSoTimeout(Timeout.ofSeconds(5))
            .build();

    final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
            HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig);

    client.start();

    final HttpHost target = new HttpHost("localhost", 7070, "https");
    final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
    final AsyncClientEndpoint endpoint = leaseFuture.get(30, TimeUnit.SECONDS);
    try {
        final String[] requestUris = new String[] {"/test.html"};

        final CountDownLatch latch = new CountDownLatch(requestUris.length);
        for (final String requestUri: requestUris) {
            final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
            endpoint.execute(
                    SimpleRequestProducer.create(request),
                    SimpleResponseConsumer.create(),
                    new FutureCallback<SimpleHttpResponse>() {

                        @Override
                        public void completed(final SimpleHttpResponse response) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + response.getCode());
                            System.out.println(response.getBody());
                        }

                        @Override
                        public void failed(final Exception ex) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + ex);
                        }

                        @Override
                        public void cancelled() {
                            latch.countDown();
                            System.out.println(requestUri + " cancelled");
                        }

                    });
        }
        latch.await();
    } finally {
        endpoint.releaseAndReuse();
    }

    System.out.println("Shutting down");
    client.shutdown(ShutdownType.GRACEFUL);

此示例适用于具有有效证书的站点,但如果我想尝试证书已过期/自签名的站点,则会引发以下异常

javax.net.ssl.SSLHandshakeException:一般 SSLEngine 问题 javax.net.ssl.SSLHandshakeException:一般 SSLEngine 问题 sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478) 在 sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535) 在 sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1214) 在 sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1186) 在 javax.net.ssl.SSLEngine.wrap(SSLEngine.java:469) 在 org.apache.hc.core5.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:256) 在 org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:294) 在 org.apache.hc.core5.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:502) 在 org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:112) 在 org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50) 在 org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173) 在 org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123) 在 org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:80) 在 org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) 在 java.lang.Thread.run(Thread.java:748) 引起: javax.net.ssl.SSLHandshakeException:一般 SSLEngine 问题在 sun.security.ssl.Alerts.getSSLException(Alerts.java:192) 在 sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728) 在 sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304) 在 sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) 在 sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) 在 sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) 在 sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) 在 sun.security.ssl.Handshaker$1.run(Handshaker.java:966) 在 sun.security.ssl.Handshaker$1.run(Handshaker.java:963) 在 java.security.AccessController.doPrivileged(Native Method) 在 sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) 在 org.apache.hc.core5.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:274) 在 org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:331) ... 8 更多原因:sun.security.validator.ValidatorException: PKIX 路径构建失败: sun.security.provider.certpath.SunCertPathBuilderException:无法 在以下位置找到请求目标的有效认证路径 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) 在 sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) 在 sun.security.validator.Validator.validate(Validator.java:260) 在 sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) 在 sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281) 在 sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) 在 sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ... 16 更多原因: sun.security.provider.certpath.SunCertPathBuilderException:无法 在以下位置找到请求目标的有效认证路径 sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) 在 sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) 在 java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) 在 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ... 22 更多

我尝试过的: 我创建了一个信任所有证书的套接字工厂,并尝试在 connectionManager 中进行设置,但它创建了一个 CloseableHttpClient,我认为它不能用于异步多路复用,代码如下

SSLContext sslContext = SSLContextBuilder
                .create()
                .loadTrustMaterial(new TrustSelfSignedStrategy())
                .build();

        // we can optionally disable hostname verification. 
        // if you don't want to further weaken the security, you don't have to include this.
        HostnameVerifier allowAllHosts = new NoopHostnameVerifier();

        // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
        // and allow all hosts verifier.
        SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);

        Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create().register("https", connectionFactory).build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
        CloseableHttpClient build = HttpClients.custom().setConnectionManager(cm).build();

如果有任何方法或解决方法可以忽略 MinimalHttpAsyncClient 中的自签名证书,请告诉我。

【问题讨论】:

    标签: java self-signed apache-httpcomponents apache-httpasyncclient apache-httpclient-5.x


    【解决方案1】:

    首先,配置应用程序使用的 SSL 上下文。如果绝对必须这样做,强烈建议让它只信任特定的自签名证书,而不是不加选择地信任所有证书

    final SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(new TrustAllStrategy())
            .build();
    

    使用给定的 SSL 上下文创建自定义连接管理器

    final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
            .setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
            .build();
    

    使用给定的连接管理器创建自定义 HttpAsyncClient 实例

    final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
           HttpVersionPolicy.FORCE_HTTP_2, 
           H2Config.DEFAULT, 
           null, 
           ioReactorConfig, 
           connectionManager);
    

    或者,如果您只关心 HTTP/2 并且不需要具有 HTTP/1.1 回退的客户端,请考虑使用 HTTP/2 优化实现。最小的实现将以尽可能少的开销提供基本的消息传输功能(无状态管理、无身份验证、无缓存、无自动重定向)。

    final MinimalHttp2AsyncClient h2ClientMinimal = HttpAsyncClients.createHttp2Minimal(
          H2Config.DEFAULT, 
          ioReactorConfig, 
          new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE));
    

    功能齐全的实现将提供功能齐全的 HTTP/2 传输,具有经典 HttpClient 支持的所有功能,唯一的例外是透明内容解压缩:

    final HttpAsyncClient h2Client = HttpAsyncClients.customHttp2()
            .setIOReactorConfig(ioReactorConfig)
            .setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
            .build();
    

    希望对你有帮助

    【讨论】:

    • 您好,奥列格,感谢您的回答。当我尝试这个例子时,我得到 javax.net.ssl.SSLPeerUnverifiedException: Certificate for does not match common name of the certificate subject: *.abc.com 我需要验证似乎也检查主机名,请在此先感谢您帮助我
    • @Zyber 请使用NoopHostnameVerifier 禁用主机名验证。查看更新的代码 sn-ps
    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 2016-07-27
    • 2011-01-16
    • 2016-10-01
    • 2017-02-16
    • 2018-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多