为Elastic search Restclient禁用SSL验证在Java中不起作用 [英] Disabling SSL verification for Elastic search Restclient not working in Java

查看:258
本文介绍了为Elastic search Restclient禁用SSL验证在Java中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试连接到gcp框中托管的弹性搜索.要对此进行连接,需要进行SSL检查,并且我需要证书.

I am trying to connect to elastic search hosted in a gcp box. To connect to this, there is a SSL check and I need a certificate.

但是,从这些讨论中,我们可能会关闭此验证.

However from these discussions, it is possible that we can turn off this verification.

如何禁用Java中的Elasticsearch RestClient v6.7.0的SSL验证

https://discuss.elastic.co/t/host-name-do-not-match-the-certificate/186618

我试图删除验证.但是它抛出了以下错误

I had tried to remove the verification. But it throwing the following error

javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:947)
    at org.elasticsearch.client.RestClient.performRequest(RestClient.java:229)
    at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1762)
    at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1732)
    at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1694)
    at org.elasticsearch.client.RestHighLevelClient.search(RestHighLevelClient.java:1090)
    at org.dexter.lab.elasticUtils.ESUtils.getLastIndexedTimeStamp(ESUtils.java:44)
    at org.dexter.lab.druidUtils.DruidDelayChecker.main(DruidDelayChecker.java:357)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1521)
    at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:528)
    at sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1197)
    at sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1165)
    at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:469)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:265)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:305)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:509)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:120)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1709)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:318)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:970)
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:967)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1459)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:283)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:353)
    ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
    at sun.security.validator.Validator.validate(Validator.java:262)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1626)
    ... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
    ... 23 more

这就是我所做的:

我重写了功能以验证功能并返回true.这样它就不会检查了.这是该代码

I did a override to verify function and returned true. So that it won't check. This is the code for that

restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @Override
                public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                    return httpClientBuilder.setSSLHostnameVerifier(new HostnameVerifier() {
                        public boolean verify(String s, SSLSession sslSession) {
                            return true;
                        }
                    });
                }
            });

我尝试了另一种方式,就像弹性线中提到的那样

I tried with another way as well as mentioned in the elastic thread

restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @Override
                public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                    return httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
                }
            });

我已经生成了一个自签名证书,并且可以正常工作.我已启用调试日志以查看为什么需要证书.

I had generated a self signed certificate and it worked. I had enabled debug logs to see why a certificate is needed.

这些是添加证书后的日志:

These are the logs after adding certificate:

***
Found trusted certificate:
[
[
  Version: V3

其后是有关证书的详细信息.

This was followed by details about certificate.

问题是我无法为生产环境生成自签名证书,并且即使重写后,我也因为不使用证书而出现异常.

The problem is I cannot generate self signed certificate for production environment and there I am getting exceptions for not using certificate even after overriding.

有没有可能解决此问题的方法?任何帮助,我们将不胜感激.

Is there any possible work around for this ? Any help is greatly appreciated.

预先感谢

推荐答案

在您的示例中,您仅禁用了主机名验证.服务器(ElasticSearch或ElasticSearch之上的某物)正在向您发送公钥/证书,并且您的Restclient会在ssl握手期间尝试验证这一点.您需要做的是告诉RestClient,可以确定从任何人那里接收证书,但是当它收到证书时,不应该真正对其进行验证.因此,您需要一个自定义的信任管理器,其任务是验证证书,但实际上根本不验证.您需要的是 UnsafeX509ExtendedTrustManager ,请参见下面的代码段以及RestClient的用法:

In your example you only disabled the hostname verification. The server (ElasticSearch or something on top of ElasticSearch) is sending you the public key/certificate and your Restclient tries to validate that during the ssl handshake. What you need to do is tell to your RestClient that it is OK to receive a certificate from anyone but when it receives one it should not really validate it. So you need a custom trustmanager which has the task to validate the certificate but actually it doesn't validate at all. What you need is an UnsafeX509ExtendedTrustManager, see below for the code snippets and the usage with the RestClient:

选项1

/**
 * An insecure {@link UnsafeX509ExtendedTrustManager TrustManager} that trusts all X.509 certificates without any verification.
 * <p>
 * <strong>NOTE:</strong>
 * Never use this {@link UnsafeX509ExtendedTrustManager} in production.
 * It is purely for testing purposes, and thus it is very insecure.
 * </p>
 * <br>
 * Suppressed warning: java:S4830 - "Server certificates should be verified during SSL/TLS connections"
 *                                  This TrustManager doesn't validate certificates and should not be used at production.
 *                                  It is just meant to be used for testing purposes and it is designed not to verify server certificates.
 */
class UnsafeX509ExtendedTrustManager extends X509ExtendedTrustManager {

    public static final UnsafeX509ExtendedTrustManager INSTANCE = new UnsafeX509ExtendedTrustManager();
    private static final Logger LOGGER = LoggerFactory.getLogger(UnsafeX509ExtendedTrustManager.class);
    private static final X509Certificate[] EMPTY_X509_CERTIFICATES = new X509Certificate[0];
    private static final String CLIENT_CERTIFICATE_LOG_MESSAGE = "Accepting a client certificate: [{}]";
    private static final String SERVER_CERTIFICATE_LOG_MESSAGE = "Accepting a server certificate: [{}]";

    private UnsafeX509ExtendedTrustManager() {}

    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String authType) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(CLIENT_CERTIFICATE_LOG_MESSAGE, x509Certificates[0].getSubjectDN());
        }
    }

    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String authType, Socket socket) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(CLIENT_CERTIFICATE_LOG_MESSAGE, x509Certificates[0].getSubjectDN());
        }
    }

    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String authType, SSLEngine sslEngine) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(CLIENT_CERTIFICATE_LOG_MESSAGE, x509Certificates[0].getSubjectDN());
        }
    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String authType) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(SERVER_CERTIFICATE_LOG_MESSAGE, x509Certificates[0].getSubjectDN());
        }
    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String authType, Socket socket) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(SERVER_CERTIFICATE_LOG_MESSAGE, x509Certificates[0].getSubjectDN());
        }
    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String authType, SSLEngine sslEngine) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(SERVER_CERTIFICATE_LOG_MESSAGE, x509Certificates[0].getSubjectDN());
        }
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return EMPTY_X509_CERTIFICATES;
    }

}

上面的日志语句根本不是必需的,但是如果您想查看信任管理器实际收到的证书,则非常方便.

The above logging statements are not required at all, but handy if you want to see actually which certificate are received by the trustmanager.

以上信任管理器可以通过以下代码段提供给RestHighLevelClient:

The above trustmanager can be supplied to the RestHighLevelClient with the following snippet:

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{ UnsafeX509ExtendedTrustManager.INSTANCE }, null);

RestClientBuilder restClientBuilder = RestClient
        .builder(new HttpHost("localhost", 9200, "https"))
        .setHttpClientConfigCallback(httpClientBuilder -> 
                httpClientBuilder.setSSLContext(sslContext)
                                 .setSSLHostnameVerifier((host, session) -> true));

顺便说一句,我不建议您或其他任何人使用UnsafeX509ExtendedTrustManager.这是不安全的,不应在生产中完全使用.

选项2

如果您不想将自定义代码添加到代码库中,而只想轻松禁用ssl验证,则可以尝试以下代码段.它是一个可以轻松生成SSLContext或其他ssl资料的库,并且可以选择禁用ssl验证.

If you don't want to add the custom code to your code base but just only want to easily disable the ssl verification, you might want to give the following snippet a try. It is a library to easily generate the SSLContext or other ssl materials and it has the option to disable the ssl verification.

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart</artifactId>
    <version>6.6.0</version>
</dependency>

用法

SSLFactory sslFactory = SSLFactory.builder()
          .withTrustingAllCertificatesWithoutValidation()
          .withHostnameVerifier((host, session) -> true))
          .build();

RestClientBuilder restClientBuilder = RestClient
        .builder(new HttpHost("localhost", 9200, "https"))
        .setHttpClientConfigCallback(httpClientBuilder -> 
                httpClientBuilder.setSSLContext(sslFactory.getSslContext())
                                 .setSSLHostnameVerifier(sslFactory.getHostnameVerifier());

这篇关于为Elastic search Restclient禁用SSL验证在Java中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆