【问题标题】:Ignore SSL Certificate Errors with Java使用 Java 忽略 SSL 证书错误
【发布时间】:2012-08-17 02:48:03
【问题描述】:

Apache Http 客户端。可以看相关代码here

String url = "https://path/to/url/service";
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);

// Test whether to ignore cert errors
if (ignoreCertErrors){
  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) {}
    }
  };

  try {
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
  } catch (Exception e){
    e.printStackTrace();
  }
}

try {

  // Execute the method (Post) and set the results to the responseBodyAsString()
  int statusCode = client.executeMethod(method);
  resultsBody = method.getResponseBodyAsString();

} catch (HttpException e){
  e.printStackTrace();
} catch (IOException e){
  e.printStackTrace();
} finally {
  method.releaseConnection();
}

这是每个人都说用来忽略 SSL 证书错误的方法(仅将其设置为暂存,不会在生产中使用)。但是,我仍然收到以下异常/堆栈跟踪:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building unable to find valid certification path to requested target

任何提示都会很棒。如果我做错了 TrustManager,或者我应该以不同的方式执行 HTTP Post 方法,无论哪种方式。

谢谢!

【问题讨论】:

  • 请阅读您发布的问题的答案(就像我一样,很多次)。我正在按照他说的做,但仍然遇到问题。谢谢。
  • 请将您的代码粘贴为问题的一部分,以便它是独立的。像这样的小东西不需要使用 Gist/Github。
  • 'Everyone' 对此是错误的。忽略证书问题会使 SSL 从根本上不安全,特别容易受到中间人攻击。请参阅RFC 2246 中的讨论。还应该注意的是,您的链接中X509TrustManager 的实现以及我看到的大多数其他链接都不符合规范。
  • @EJP。发帖人并没有要求进行安全讲座。他想知道怎么做。

标签: java jakarta-ee ssl ssl-certificate


【解决方案1】:

首先,不要忽略证书错误。而是与他们打交道。忽略证书错误会打开与潜在 MITM 攻击的连接。这就像关闭烟雾报警器中的蜂鸣器一样,因为有时它会发出噪音......

当然,很容易说它仅用于测试代码,它不会最终投入生产,但我们都知道截止日期临近时会发生什么:代码在测试时不会显示任何错误 -> 我们可以按原样发货。如果需要,您应该设置一个测试 CA。制作起来并不难,整个过程肯定不比引入自定义代码进行开发并在生产中删除它更难。

您明显在使用 Apache Http 客户端:

HttpClient client = new HttpClient();
int statusCode = client.executeMethod(method);

然而,您正在使用您创建的 SSLContext 初始化 javax.net.ssl.HttpsURLConnection

HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

这完全独立于 Apache Http 客户端设置。

相反,您应该为 Apache Http 客户端库设置SSLContext,如this answer 中所述。如果您使用的是 Apache Http Client 3.x,则需要设置自己的 SecureProtocolSocketFactory 以使用该 SSLContext(参见示例 here)。不过值得升级到 Apache Http Client 4.x,它直接支持SSLContext

您也可以使用Pascal's answer 正确导入证书。同样,如果您按照接受的答案(凯文)对该问题进行回答,您确实会忽略该错误,但这会使连接容易受到 MITM 攻击。

【讨论】:

  • 谢谢!所以基本上,我已经编写了代码来通过加载 .properties 文件来处理不同的“环境”。我只是在 localhost.properties 中将 ignorecerterrors 设置为 true,因此它不会潜入生产环境。不过这很好,我一定会调查的。我会告诉你的!
  • 通过属性文件加载不同的环境是可行的,但是你的代码库中仍然会有一些不安全的代码(其他人可能最终会复制/粘贴)。总体而言,拥有内部测试 CA 可以使测试更加真实,无需更改代码(仅配置)。
  • 我不能 100% 确定什么是测试 CA,您介意启发一下吗?
  • 好吧,只需创建您自己的 CA 并使用它颁发证书。在您的开发环境中,设置您的服务以使用这些证书并将 CA 证书本身导入客户端的信任库。这在测试/开发环境中是可行的,并且有一些工具可以帮助您(例如 OpenSSL 的 CA.pl 或 TinyCA)。
【解决方案2】:

HttpClient 4.3,很简单,

     HttpClientBuilder cb = HttpClientBuilder.create();
     SSLContextBuilder sslcb = new SSLContextBuilder();
     sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), new TrustSelfSignedStrategy());
     cb.setSslcontext(sslcb.build());
     CloseableHttpClient httpclient = cb.build();

应该可以解决你的问题

【讨论】:

    【解决方案3】:

    如果你真的想忽略这对我有用的一切:

    SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            return true;
        }
    }).build();
    HostnameVerifier hnv = new NoopHostnameVerifier();      
    SSLConnectionSocketFactory sslcf = new SSLConnectionSocketFactory(sslContext, hnv);     
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcf).build()
    

    【讨论】:

      【解决方案4】:

      忽略证书有其自身的危害,因为相同的代码可以在生产环境中移动,并可能造成严重破坏。

      下面的例子是 Jersey Rest Client

      private static final com.sun.jersey.api.client.Client client = com.sun.jersey.api.client.Client.create(configureClient());
      final com.sun.jersey.api.client.WebResource webResource = client.resource("url");
      try {
          com.sun.jersey.api.client.ClientResponse response = webResource.type(MediaType.APPLICATION_JSON_TYPE)
                                  .accept(MediaType.APPLICATION_JSON_TYPE)
                                  .get(com.sun.jersey.api.client.ClientResponse.class);
      }catch(com.sun.jersey.api.client.ClientHandlerException che){
          che.printStackTrace();  
      }
      

      忽略证书可以如下:

      public static ClientConfig configureClient() {
          TrustManager[ ] certs = new TrustManager[ ] {
                  new X509TrustManager() {
                      public X509Certificate[] getAcceptedIssuers() {
                          return null;
                      }
                      public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
                      public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
                  }
          };
          SSLContext ctx = null;
          try {
              ctx = SSLContext.getInstance("SSL");
              ctx.init(null, certs, new SecureRandom());
          } catch (java.security.GeneralSecurityException ex) {
          }
          HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
      
          ClientConfig config = new DefaultClientConfig();
          try {
              config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
                      new HostnameVerifier() {
                          public boolean verify(String hostname, SSLSession session) {
                              return true;
                          }
                      },
                      ctx
              ));
          } catch(Exception e) {
          }
      
          return config;
      }
      

      【讨论】:

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