9

Apache Http 客户端。您可以在此处查看相关代码:

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 方法,无论哪种方式。

谢谢!

4

4 回答 4

14

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

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

您显然正在使用 Apache Http 客户端:

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

然而,你正在javax.net.ssl.HttpsURLConnectionSSLContext你创建的初始化:

HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

这完全独立于 Apache Http Client 设置。

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

您还可以使用Pascal 的答案正确导入证书。同样,如果您遵循该问题的公认答案(凯文),您确​​实会忽略该错误,但这会使连接容易受到 MITM 攻击。

于 2012-08-21T18:28:49.893 回答
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();

那应该可以解决您的问题

于 2014-09-02T09:41:07.130 回答
1

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

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()
于 2017-09-28T12:40:29.397 回答
0

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

下面的例子是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;
}
于 2017-03-16T01:53:31.790 回答