【问题标题】:How to make Jersey ignore ssl certificate error?如何让 Jersey 忽略 ssl 证书错误?
【发布时间】:2021-02-18 01:51:11
【问题描述】:

错误追踪:

javax.ws.rs.ProcessingException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target##
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:287)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:252)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:701)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:697)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)
at com.xxx.rest.RestClient.execRequest(RestClient.java:49)
at com.xxx.RestClientTest.test(RestClientTest.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: javax.net.ssl.SSLHandshakeException: 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.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1513)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:394)
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
... 36 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:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
... 51 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:382)
... 57 more

像 apache httpclient 等所有其他客户端一样,默认情况下,Jersey 会检查 SSL 证书,这是正确的方式。但是在某些情况下,比如开发阶段,很可能是我们没有 CA 信任的 SSL 证书。那么问题来了,我们怎样才能让 Jersey 忽略 SSL 证书错误呢?

【问题讨论】:

    标签: jersey ssl-certificate apache-httpclient-4.x


    【解决方案1】:

    请注意,信任所有证书风险极大做的时候要小心

    以下代码与yukuan's answer 中显示的代码没有太大区别。但是,以下解决方案仅使用 JAX-RS Client API。理论上,它也应该与其他 JAX-RS 实现一起使用:

    TrustManager[] trustManager = new X509TrustManager[] { new X509TrustManager() {
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    
        @Override
        public void checkClientTrusted(X509Certificate[] certs, String authType) {
    
        }
    
        @Override
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
    
        }
    }};
    
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustManager, null);
    
    Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
    

    注意 1: 在撰写本文时,上述标准解决方案不适用于 RESTEasy。 RESTEasy 将来自 Apache HttpComponents 项目的 HTTP 调用委托给 HttpClient。要使用 RESTEasy 信任所有证书,必须自定义 HttpClient。有关更多详细信息,请查看此answer

    注意 2:您可能会发现 https://badssl.com 是一个有用的资源,可用于针对不良 SSL 配置测试客户端。

    【讨论】:

      【解决方案2】:
      package com.xxxxxxx.rest;
      
      import java.security.KeyManagementException;
      import java.security.NoSuchAlgorithmException;
      import java.security.cert.X509Certificate;
      import java.util.Properties;
      
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.X509TrustManager;
      import javax.ws.rs.client.Client;
      import javax.ws.rs.client.ClientBuilder;
      
      import org.glassfish.jersey.client.JerseyClientBuilder;
      
      public class RestClient {
      
          private Client client;
      
          public RestClient(Properties properties) {
              super();
              ClientBuilder clientBuilder = new JerseyClientBuilder();
              SSLContext sslContext = null;
              TrustManager[] trustAllCerts = new X509TrustManager[] { new X509TrustManager() {
                  @Override
                  public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                      return null;
                  }
      
                  @Override
                  public void checkClientTrusted(X509Certificate[] certs, String authType) {
                  }
      
                  @Override
                  public void checkServerTrusted(X509Certificate[] certs, String authType) {
                  }
              } };
              try {
                  sslContext = SSLContext.getInstance("SSL");
                  sslContext.init(null, trustAllCerts, null);
              } catch (NoSuchAlgorithmException | KeyManagementException e) {
              }
              clientBuilder.sslContext(sslContext);
              client = clientBuilder.build();
          }
      
          public <T> T execRequest(String uri, Class<T> type) {
              return client.target(uri).request().get(type);
          }
      }
      

      【讨论】:

      • 以防我以后忘记。
      • my approach有什么区别?
      • 显然我不经常检查我的 SO LOL,这与您的方法没有什么不同,只是提前 4 个半小时(同一分钟我发布了我的问题,只是为了个人提醒)
      【解决方案3】:

      与其试图忽略错误,不如一开始就避免它。添加代码作为解决方法是有风险的,因为轶事经验表明代码最终会投入生产。

      出于开发目的,您应该创建一个合适的信任库,以便您的开发证书受到信任。 this related question 的公认答案记录了如何为这种情况创建这样的信任库。如果您手头有服务器证书,几乎可以肯定,您可以避免浏览器步骤并编写所有内容。

      理想情况下,如果找不到证书(这样您就不会意外地将开发证书配置部署到生产机器上),这会导致进程失败。

      【讨论】:

        【解决方案4】:

        你可以试试这样的:

            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
                public void checkClientTrusted(X509Certificate[] certs, String authType) { }
                public void checkServerTrusted(X509Certificate[] certs, String authType) { }
            }};
        
            // Install the all-trusting trust manager
            SSLContext sc;
            try {
                sc = SSLContext.getInstance("SSL");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            } catch (Exception e) {
                e.printStackTrace();
            }
        
            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        

        【讨论】:

          猜你喜欢
          • 2011-06-12
          • 2019-09-05
          • 1970-01-01
          • 2012-08-17
          • 1970-01-01
          • 2019-09-02
          • 2015-04-22
          • 1970-01-01
          相关资源
          最近更新 更多