【问题标题】:Ignore self-signed ssl cert using Jersey Client [duplicate]使用 Jersey 客户端忽略自签名 ssl 证书 [重复]
【发布时间】:2011-08-28 05:26:27
【问题描述】:

我正在使用 Jersey 客户端库对运行在 jboss 上的 rest 服务运行测试。 我使用自签名证书在服务器上(在 localhost 上运行)很好地设置了 https。

但是,每当我使用 https url 运行测试时,我都会收到以下错误:

com.sun.jersey.api.client.ClientHandlerException: 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 com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:131)
    at com.sun.jersey.api.client.Client.handle(Client.java:629)
    at com.sun.jersey.oauth.client.OAuthClientFilter.handle(OAuthClientFilter.java:137)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:601)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:459)
    at test.helper.Helper.sendSignedRequest(Helper.java:174)
    ... And so on

我知道这是因为我的自签名证书不在 java 密钥库中。有什么办法可以让Client 不检查 ssl 证书的有效性而不管怎样都使用它?

这段代码只会在测试服务器上运行,所以我不想在每次设置新测试服务器时都为添加新的受信任证书而烦恼。

这是调用的代码:

OAuthParameters params = new OAuthParameters();

// baseline OAuth parameters for access to resource
params.signatureMethod(props.getProperty("signature_method"));
params.consumerKey(props.getProperty("consumer_key"));
params.setToken(props.getProperty("token"));
params.setVersion("1.0");
params.nonce();

// OAuth secrets to access resource
OAuthSecrets secrets = new OAuthSecrets();
secrets.consumerSecret(props.getProperty("consumer_secret"));
secrets.setTokenSecret(props.getProperty("token_secret"));

// Jersey client to make REST calls to token services
Client client = Client.create();

// OAuth test server resource
WebResource resource = client.resource(props.getProperty("url"));

// if parameters and secrets remain static, filter cab be added to each web resource
OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);

// filter added at the web resource level
resource.addFilter(filter);
WebResource.Builder wbr = resource.getRequestBuilder().accept(props.getProperty("accept"));

return wbr.get(ClientResponse.class);

任何帮助将不胜感激。

【问题讨论】:

标签: java ssl ssl-certificate jersey


【解决方案1】:

在一些旧的 stackoverflow 问题中进行了一些搜索和拖网搜索后,我在之前提出的 SO 问题中找到了解决方案:

这是我最终使用的代码。

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
    public X509Certificate[] getAcceptedIssuers(){return null;}
    public void checkClientTrusted(X509Certificate[] certs, String authType){}
    public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
    ;
}

【讨论】:

  • 克里斯,你有适用于 Java 7 的版本吗?在您的代码中,您根本没有提供密钥库,您是否使用 -D 向 VM 指定了使用 SSL 属性的密钥库?
  • 我没有指定 KeyStore。我在没有任何其他 VM 争论的情况下使用了上面的代码。如果我认为代码有效,因为它不检查它是否由受信任的签名者签名,它只检查它是否格式正确。
  • 我必须将 public X509Certificate[] getAcceptedIssuers(){return null;} 替换为 public X509Certificate[] getAcceptedIssuers(){return new X509Certificate[0];} 才能使其正常工作。
  • 此答案设置 all Java 中的 HTTPS 连接以忽略 SSL 证书...这可能不是您想要的,因为它可能只为客户端执行有问题,如@eitan 和其他人的另一个答案所示。
  • 这个答案也不符合TrustManager.getAcceptedIssuers()的约定。不要使用。
【解决方案2】:

对于 Jersey 2.*(在 2.7 上测试)和 java 8:

import java.security.cert.CertificateException; 
import java.security.cert.X509Certificate; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 

public static Client ignoreSSLClient() throws Exception {

    SSLContext sslcontext = SSLContext.getInstance("TLS");

    sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }}, new java.security.SecureRandom());

    return ClientBuilder.newBuilder()
                        .sslContext(sslcontext)
                        .hostnameVerifier((s1, s2) -> true)
                        .build();
}

【讨论】:

  • 导入包从哪里来? java 还是 javax?
  • 导入 java.security.cert.CertificateException;导入 java.security.cert.X509Certificate;导入 javax.net.ssl.SSLContext;导入 javax.net.ssl.TrustManager;导入 javax.net.ssl.X509TrustManager;
  • 我发现主机名验证是可选的。这可能是因为 TLS 不需要此类检查,而不是例如 https。
【解决方案3】:

我遇到了同样的问题,不想全局设置,所以我使用了与上面相同的 TrustManager 和 SSLContext 代码,我只是将客户端更改为使用特殊属性创建

 ClientConfig config = new DefaultClientConfig();
 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
     new HostnameVerifier() {
         @Override
         public boolean verify( String s, SSLSession sslSession ) {
             // whatever your matching policy states
         }
     }
 ));
 Client client = Client.create(config);

【讨论】:

【解决方案4】:

此代码只会在测试服务器上运行,所以我不希望 每次我们设置一个新的受信任证书时都会遇到麻烦 新的测试服务器。

这种代码最终会在生产中找到自己的方式(如果不是来自您,阅读此问题的其他人会将建议的不安全信任管理器复制并粘贴到他们的应用程序中)。当您有截止日期时,很容易忘记删除此类代码,因为它不会显示为问题。

如果您担心每次拥有测试服务器时都必须添加新证书,请创建自己的小型 CA,为使用该 CA 的测试服务器颁发所有证书,并将该 CA 证书导入您的客户端信任存储区。 (即使您不在本地环境中处理在线证书吊销之类的事情,这也肯定比使用允许任何事情通过的信任管理器更好。)

有一些工具可以帮助您执行此操作,例如 TinyCAXCA

【讨论】:

【解决方案5】:

由于我是 stackoverflow 的新手,并且在评论其他人的答案方面声誉较低,因此我将 Chris Salij 建议的解决方案进行了一些对我有用的修改。

SSLContext ctx = null;
TrustManager[] trustAllCerts = new X509TrustManager[]{new X509TrustManager(){
    public X509Certificate[] getAcceptedIssuers(){return null;}
    public void checkClientTrusted(X509Certificate[] certs, String authType){}
    public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};
try {
    ctx = SSLContext.getInstance("SSL");
    ctx.init(null, trustAllCerts, null);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
    LOGGER.info("Error loading ssl context {}", e.getMessage());
}

SSLContext.setDefault(ctx);

【讨论】:

【解决方案6】:

对于 Jersey 2.x 上没有 lambdas 的任何人,使用这个:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;

public static Client getUnsecureClient() throws Exception 
{
    SSLContext sslcontext = SSLContext.getInstance("TLS");
    sslcontext.init(null, new TrustManager[]{new X509TrustManager() 
    {
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}
            public X509Certificate[] getAcceptedIssuers()
            {
                return new X509Certificate[0];
            }

    }}, new java.security.SecureRandom());


    HostnameVerifier allowAll = new HostnameVerifier() 
    {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier(allowAll).build();
}

JRE 1.7 上使用 jersey-client 2.11 进行测试。

【讨论】:

    【解决方案7】:

    只需添加与导入相同的代码。还包含编译所需的未实现代码。我最初很难找出为此代码导入的内容。还为 X509Certificate 添加了正确的包。通过反复试验得到了这个:

    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import javax.security.cert.CertificateException;
    import javax.security.cert.X509Certificate;
    import javax.ws.rs.core.MultivaluedMap;
    
     TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
    
         public java.security.cert.X509Certificate[] getAcceptedIssuers() {
             java.security.cert.X509Certificate[] chck = null;
             ;
             return chck;
         }
    
         public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                 throws CertificateException {
             // TODO Auto-generated method stub
    
         }
    
         public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                 throws CertificateException {
    
         }
    
         public void checkClientTrusted(
                 java.security.cert.X509Certificate[] arg0, String arg1)
                         throws java.security.cert.CertificateException {
             // TODO Auto-generated method stub
    
         }
    
         public void checkServerTrusted(
                 java.security.cert.X509Certificate[] arg0, String arg1)
                         throws java.security.cert.CertificateException {
             // TODO Auto-generated method stub
    
         }
     } };
    
     // Install the all-trusting trust manager
     try {
         SSLContext sc = SSLContext.getInstance("TLS");
         sc.init(null, trustAllCerts, new SecureRandom());
         HttpsURLConnection
         .setDefaultSSLSocketFactory(sc.getSocketFactory());
     } catch (Exception e) {
         ;
     }
    

    【讨论】:

    • 你只需要@Override java.security.cert.* 的东西。
    【解决方案8】:

    对于泽西岛 2.*:

    Client client = ClientBuilder.newBuilder()
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    }).build();
    

    ->https://jersey.java.net/documentation/latest/migration.html

    【讨论】:

    • 用 lambda 进一步简化:Client client = ClientBuilder.newBuilder() .hostnameVerifier((hostname, session) -> true) .build();
    【解决方案9】:

    我注意到,当将 Apache http 客户端配置与池管理器一起使用时,接受的答案不起作用。

    在这种情况下,ClientConfig.sslContextClientConfig.hostnameVerifier 设置器似乎被默默地忽略了。因此,如果您将连接池与 apache 客户端 http 客户端配置一起使用,您应该能够使用以下代码来忽略 ssl 验证:

      ClientConfig clientConfig = new ClientConfig();
      // ... configure your clientConfig
      SSLContext sslContext = null;
      try {
        sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, new TrustManager[] {
            new X509TrustManager() {
              @Override
              public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
              }
    
              @Override
              public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
              }
    
              @Override
              public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[] {};
              }
            }
        }, null);
      } catch (NoSuchAlgorithmException e) {
        //logger.debug("Ignoring 'NoSuchAlgorithmException' while ignoring ssl certificate validation.");
      } catch (KeyManagementException e) {
        //logger.debug("Ignoring 'KeyManagementException' while ignoring ssl certificate validation.");
      }
      Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
          .register("http", PlainConnectionSocketFactory.getSocketFactory())
          .register("https", new SSLConnectionSocketFactory(sslContext, new AbstractVerifier() {
            @Override
            public void verify(String host, String[] cns, String[] subjectAlts) {
            }
          }))
          .build();
      connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
      clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
      return ClientBuilder.newClient(clientConfig);
    

    【讨论】:

      【解决方案10】:

      适用于泽西岛 1.X

          TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
      
              public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {}
      
              public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {}
      
              public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
                  // or you can return null too
                  return new java.security.cert.X509Certificate[0];
              }
          }};
      
      
          SSLContext sc = SSLContext.getInstance("TLS");
          sc.init(null, trustAllCerts, new SecureRandom());
          HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
          HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
              public boolean verify(String string, SSLSession sslSession) {
                  return true;
              }
          });
      

      【讨论】:

      • 你也不能返回 null。请参阅 Javadoc。
      • 请测试,你会看到结果!
      • 有时您可能会返回 null 以正常工作。请阅读 cmets。 stackoverflow.com/a/6055903/2590960
      • 这一切都无关紧要。当 Javadoc 与它们两者相矛盾时,您不能在另一个 StackOverflow 答案中引用 StackOverflow 答案。此处或其他地方返回 null 的任何答案都与此答案一样错误。请阅读 Javadoc 中的内容并遵守所需的合同。
      【解决方案11】:

      好的,我只想添加我的类,只是因为将来可能会有一些开发人员想要连接到 Netbackup 服务器(或类似的东西)并在忽略 SSL 证书的情况下从 Java 做一些事情。这对我有用,我们使用 Windows 活动目录对 Netbackup 服务器进行身份验证。

      public static void main(String[] args) throws Exception {
          SSLContext sslcontext = null;
          try {
              sslcontext = SSLContext.getInstance("TLS");
          } catch (NoSuchAlgorithmException ex) {
              Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
          }
          try {
              sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
                  public X509Certificate[] getAcceptedIssuers() {
                      return new X509Certificate[0];
                  }
                  @Override
                  public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                      //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
                  }
      
                  @Override
                  public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                      //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
                  }
              }}, new java.security.SecureRandom());
          } catch (KeyManagementException ex) {
              Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
          }
          //HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().credentials(username, password).build();
          ClientConfig clientConfig = new ClientConfig();
          //clientConfig.register(feature);
          Client client = ClientBuilder.newBuilder().withConfig(clientConfig)
                  .sslContext(sslcontext)
                  .hostnameVerifier((s1, s2) -> true)
                  .build();
      
          //String the_url = "https://the_server:1556/netbackup/security/cacert";
          String the_token;
          {
              String the_url = "https://the_server:1556/netbackup/login";
              WebTarget webTarget = client.target(the_url);
      
              Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
              String jsonString = new JSONObject()
                      .put("domainType", "NT")
                      .put("domainName", "XX")
                      .put("userName", "the username")
                      .put("password", "the password").toString();
              System.out.println(jsonString);
              Response response = invocationBuilder.post(Entity.json(jsonString));
              String data = response.readEntity(String.class);
              JSONObject jo = new JSONObject(data);
              the_token = jo.getString("token");
              System.out.println("token is:" + the_token);
      
          }
          {
              String the_url = "https://the_server:1556/netbackup/admin/jobs/1122012"; //job id 1122012 is an example
              WebTarget webTarget = client.target(the_url);
              Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, the_token).header(HttpHeaders.ACCEPT, "application/vnd.netbackup+json;version=1.0");
              Response response = invocationBuilder.get();
              System.out.println("response status:" + response.getStatus());
              String data = response.readEntity(String.class);
              //JSONObject jo = new JSONObject(data);
              System.out.println(data);
          }
      }
      

      我知道它可以被认为是题外话,但我敢打赌,尝试连接到 Netbackup 服务器的开发人员可能会在这里结束。顺便说一句,非常感谢这个问题的所有答案! 我正在谈论的规范是 heretheir code samples (目前)缺少一个 Java 示例。

      ***这当然是不安全的,因为我们忽略了证书!

      【讨论】:

        【解决方案12】:

        使用此代码为我工作。可能适用于 Java 1.7

            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
        
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    // TODO Auto-generated method stub
                    return null;
                }
        
                @Override
                public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {
                    // TODO Auto-generated method stub
        
                }
        
                @Override
                public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {
                    // TODO Auto-generated method stub
        
                }
            }};
        
            // Install the all-trusting trust manager
            try {
                SSLContext sc = SSLContext.getInstance("TLS");
                sc.init(null, trustAllCerts, new SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            } catch (Exception e) {
                ;
            }
        

        【讨论】:

        • 这个答案与 Chris Salij 的答案相同,只是它更冗长并且在几个月后得到了回答。
        猜你喜欢
        • 2016-04-09
        • 2017-02-13
        • 1970-01-01
        • 2021-04-07
        • 1970-01-01
        • 2010-11-13
        • 2011-05-24
        • 2016-10-01
        • 1970-01-01
        相关资源
        最近更新 更多