【问题标题】:How to ignore SSL certificate errors in Apache HttpClient 4.0如何忽略 Apache HttpClient 4.0 中的 SSL 证书错误
【发布时间】:2011-02-11 18:55:29
【问题描述】:

如何绕过 Apache HttpClient 4.0 的无效 SSL 证书错误?

【问题讨论】:

  • 应该注意的是,这个问题的答案并没有比所问的更多:它们让你忽略错误但不能解决根本问题(有点像从烟雾报警器而不是灭火)。证书的目的是确保 SSL/TLS 连接的安全性,忽略这些错误会引入 MITM 攻击的漏洞。使用测试证书而不是忽略错误。
  • “就像从烟雾报警器中取出电池一样”您可能会让其他开发人员从怀疑中受益,并假设他们知道自己在做什么。也许这个问题的动机是本地测试,并且 OP 希望运行一个快速测试,而不需要经历建立一个简单的 SSL 环境所需的大量 Java 样板。也许有人可以直接回答这个问题,而不必参加“比你更神圣”的演讲。
  • 即我们公司内部的 JIRA 服务器有一些“基于 Windows 安全策略的证书”,它在域中包含的 Windows 机器上有效,在其他机器上无效。我无法控制此策略,但仍想调用 JIRA REST API。
  • @Bruno 在处理小厨房火灾时无法在 30-60 分钟内禁用烟雾探测器,这表明我认为某些法律官员在某些时候对使用模式缺乏洞察力近于犯罪。有“从烟雾报警器中取出电池”的概念证明了这一点。我对必须获得证书才能进行一个我知道没有安全后果的简单测试感到同样程度的愤怒。这个问题的存在证明了这一点。

标签: java ssl apache-httpclient-4.x


【解决方案1】:

所有其他答案要么已弃用,要么不适用于 HttpClient 4.3。

这是一种在构建 http 客户端时允许所有主机名的方法。

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setHostnameVerifier(new AllowAllHostnameVerifier())
    .build();

或者,如果您使用的是 4.4 或更高版本,更新后的调用如下所示:

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
    .build();

【讨论】:

  • 感谢您的回答,我想知道我在 Android compile("org.apache.httpcomponents:httpclient:4.3.4") 中使用的 HttpsClients 是哪个包,但是这个类没有'不出现。
  • 它的包是 org.apache.http.impl.client.HttpClients 。
  • 这可以解决主机名不匹配的问题(我假设),但是当证书未由受信任的机构签名时,它似乎不起作用。
  • @twm 这就是为什么它说它“允许所有主机名”,信任问题需要不同的配置。
  • @eis,我指出这个答案在某些情况下解决了原始问题,但在其他情况下没有解决。
【解决方案2】:

您需要使用自己的 TrustManager 创建 SSLContext 并使用此上下文创建 HTTPS 方案。这是代码,

SSLContext sslContext = SSLContext.getInstance("SSL");

// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                    System.out.println("getAcceptedIssuers =============");
                    return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkClientTrusted =============");
            }

            public void checkServerTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkServerTrusted =============");
            }
} }, new SecureRandom());

SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);

// apache HttpClient version >4.2 should use BasicClientConnectionManager
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm);

【讨论】:

  • 假设我不想为我的网站购买有效的 SSL 证书而只想使用它,这段代码可以提供帮助吗?为什么我没有看到需要 URL 或需要异常处理的任何部分?
  • 嗯,它告诉我'new SSLSocketFactory(ssslCont)' 需要一个 KeyStore,而不是 SSLContext。我错过了什么吗?
  • 我收到无法将 X509TrustManager 强制转换为 TrustManager 的错误。
  • 确保导入正确的包,即从 org.apache.http。
  • 任何人都知道如何使用HttpClientBuilder 将所有这些放在一起吗?
【解决方案3】:

Apache HttpClient 4.5.5

HttpClient httpClient = HttpClients
            .custom()
            .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .build();

未使用过时的 API。

简单的可验证测试用例:

package org.apache.http.client.test;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

public class ApacheHttpClientTest {

    private HttpClient httpClient;

    @Before
    public void initClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
        httpClient = HttpClients
                .custom()
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
    }

    @Test
    public void apacheHttpClient455Test() throws IOException {
        executeRequestAndVerifyStatusIsOk("https://expired.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://wrong.host.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://self-signed.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://untrusted-root.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://revoked.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://pinning-test.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://sha1-intermediate.badssl.com");
    }

    private void executeRequestAndVerifyStatusIsOk(String url) throws IOException {
        HttpUriRequest request = new HttpGet(url);

        HttpResponse response = httpClient.execute(request);
        int statusCode = response.getStatusLine().getStatusCode();

        assert statusCode == 200;
    }
}

【讨论】:

  • 谢谢!只需在此答案中将TrustAllStrategy.INSTANCE 更改为TrustSelfSignedStrategy.INSTANCE
  • 这对我不起作用。 javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security。 provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径
  • @ggb667 我没有找到TrustAllStrategy.INSTANCE,但我尝试自己实现它:new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true).build(),它已经奏效了。
  • .setSSLContext() 4.5.6 apache 依赖项中的实际抛出和错误?将其更改为 .setSslContext() 会使错误消失?除非他们在 4.5.6 中更改它,否则它应该是带有小写“Ssl”的 .setSslContext()
【解决方案4】:

只需要使用较新的 HttpClient 4.5 来执行此操作,而且自 4.4 以来他们似乎已经弃用了一些东西,所以这是适用于我并使用最新 API 的 sn-p:

final SSLContext sslContext = new SSLContextBuilder()
        .loadTrustMaterial(null, (x509CertChain, authType) -> true)
        .build();

return HttpClientBuilder.create()
        .setSSLContext(sslContext)
        .setConnectionManager(
                new PoolingHttpClientConnectionManager(
                        RegistryBuilder.<ConnectionSocketFactory>create()
                                .register("http", PlainConnectionSocketFactory.INSTANCE)
                                .register("https", new SSLConnectionSocketFactory(sslContext,
                                        NoopHostnameVerifier.INSTANCE))
                                .build()
                ))
        .build();

【讨论】:

  • 为我工作也为 httpclient 4.5.2
  • 这是最新的 HttpClient 4.5
【解决方案5】:

为了记录,HttpClient 4.1 有一个更简单的方法来完成同样的事情

    SSLSocketFactory sslsf = new SSLSocketFactory(new TrustStrategy() {

        public boolean isTrusted(
                final X509Certificate[] chain, String authType) throws CertificateException {
            // Oh, I am easy...
            return true;
        }

    });

【讨论】:

  • 您是否缺少此示例中的某些代码?也许调用 httpClient.set...?
  • httpclient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, sslsf));
  • SSLSocketFactory 在 HttpClient 4.3 中已弃用
  • 如果使用Java 8,你甚至可以new SSLSocketFactory((chain, authType) -&gt; true);
【解决方案6】:

备案,用httpclient 4.3.6测试,兼容fluent api的Executor:

CloseableHttpClient httpClient = HttpClients.custom().
                    setHostnameVerifier(new AllowAllHostnameVerifier()).
                    setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
                    {
                        public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
                        {
                            return true;
                        }
                    }).build()).build();

【讨论】:

  • 对于 HttpClient 4.4 以上,你必须这样做——并且可能还需要使用 SSLContext 创建一个 SSLConnectionSocketFactory,并在 Registry&lt;ConnectionSocketFactory&gt; 中定义它,如果你要去的话创建一个PoolingHttpClientConnectionManager。其他答案更受欢迎,但不适用于 HttpClient 4.4。
  • 与 httpclient-4.3.5.jar 完全一样。
  • 适用于 httpclient 4.3.2
【解决方案7】:

对于 Apache HttpClient 4.4:

HttpClientBuilder b = HttpClientBuilder.create();

SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
        return true;
    }
}).build();
b.setSslcontext( sslContext);

// or SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.getSocketFactory())
        .register("https", sslSocketFactory)
        .build();

// allows multi-threaded use
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
b.setConnectionManager( connMgr);

HttpClient client = b.build();

这是从我们的实际工作实现中提取的。

其他答案很流行,但对于 HttpClient 4.4,它们不起作用。我花了几个小时尝试和耗尽各种可能性,但似乎在 4.4 版本中出现了极其重大的 API 更改和重新定位。

另请参阅:http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/

希望有帮助!

【讨论】:

    【解决方案8】:

    如果您只想摆脱无效的主机名错误,您可以这样做:

    HttpClient httpClient = new DefaultHttpClient();
    SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager()
        .getSchemeRegistry().getScheme("https").getSocketFactory();
    sf.setHostnameVerifier(new AllowAllHostnameVerifier());
    

    【讨论】:

    • 自 4.1 起,sf.setHostnameVerifier 方法已被弃用。另一种方法是使用其中一个构造函数。例如:SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    【解决方案9】:

    我们使用的是 HTTPClient 4.3.5,我们尝试了 stackoverflow 上几乎所有的解决方案,但没有, 经过思考和解决问题后,我们得出以下完美运行的代码, 只需在创建 HttpClient 实例之前添加它。

    发出post请求时调用的一些方法......

    SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });
    
        SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(builder.build(),
                SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
        HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSF).build();
        HttpPost postRequest = new HttpPost(url);
    

    以正常形式继续您的请求

    【讨论】:

      【解决方案10】:

      对于 fluent 4.5.2,我必须进行以下修改才能使其正常工作。

      try {
          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) {  }
          }
          };
      
          SSLContext sc = SSLContext.getInstance("SSL");
          sc.init(null, trustAllCerts, new SecureRandom());
          CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSslcontext(sc).build();
      
          String output = Executor.newInstance(httpClient).execute(Request.Get("https://127.0.0.1:3000/something")
                                            .connectTimeout(1000)
                                            .socketTimeout(1000)).returnContent().asString();
          } catch (Exception e) {
          }
      

      【讨论】:

      • 这是唯一对我有用的解决方案。在升级到 4.5 并尝试此之前,我尝试了 4.3 和 4.4 的上述解决方案。
      【解决方案11】:

      我就是这样做的——

      1. 创建我自己的 MockSSLSocketFactory(附在下面的类)
      2. 用它来初始化 DefaultHttpClient。如果使用代理,则需要提供代理设置。

      初始化 DefaultHTTPClient -

      SchemeRegistry schemeRegistry = new SchemeRegistry();
          schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
          schemeRegistry.register(new Scheme("https", 443, new MockSSLSocketFactory()));
          ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
      
          DefaultHttpClient httpclient = new DefaultHttpClient(cm);
      

      模拟 SSL 工厂 -

      public class MockSSLSocketFactory extends SSLSocketFactory {
      
      public MockSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
          super(trustStrategy, hostnameVerifier);
      }
      
      private static final X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
          @Override
          public void verify(String host, SSLSocket ssl) throws IOException {
              // Do nothing
          }
      
          @Override
          public void verify(String host, X509Certificate cert) throws SSLException {
              //Do nothing
          }
      
          @Override
          public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
              //Do nothing
          }
      
          @Override
          public boolean verify(String s, SSLSession sslSession) {
              return true; 
          }
      };
      
      private static final TrustStrategy trustStrategy = new TrustStrategy() {
          @Override
          public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
              return true;
          }
      };
      }
      

      如果在代理后面,需要这样做 -

      HttpParams params = new BasicHttpParams();
          params.setParameter(AuthPNames.PROXY_AUTH_PREF, getClientAuthPrefs());
      
      DefaultHttpClient httpclient = new DefaultHttpClient(cm, params);
      
      httpclient.getCredentialsProvider().setCredentials(
                              new AuthScope(proxyHost, proxyPort),
                              new UsernamePasswordCredentials(proxyUser, proxyPass));
      

      【讨论】:

      • 如果您将来包含导入内容会有所帮助。有两个不同的类。
      【解决方案12】:

      ZZ Coder's answer 的扩展中,覆盖主机名验证器会很好。

      // ...
      SSLSocketFactory sf = new SSLSocketFactory (sslContext);
      sf.setHostnameVerifier(new X509HostnameVerifier() {
          public boolean verify(String hostname, SSLSession session) {
              return true;
          }
      
          public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
          }
      
          public void verify(String host, X509Certificate cert) throws SSLException {
          }
      
          public void verify(String host, SSLSocket ssl) throws IOException {
          }
      });
      // ...
      

      【讨论】:

      • 你可以通过sf.setHostnameVerifier(new AllowAllHostnameVerifier());实现同样的目标
      • 自 4.1 起 sf.setHostnameVerifier 已被弃用。另一种方法是使用其中一个构造函数。例如:SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
      【解决方案13】:

      使用带有 Fluent API 的 HttpClient 4.5.5 测试

      final SSLContext sslContext = new SSLContextBuilder()
          .loadTrustMaterial(null, (x509CertChain, authType) -> true).build();
      
      CloseableHttpClient httpClient = HttpClients.custom()
          .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
          .setSSLContext(sslContext).build();
      
      String result = Executor.newInstance(httpClient)
          .execute(Request.Get("https://localhost:8080/someapi")
          .connectTimeout(1000).socketTimeout(1000))
          .returnContent().asString();
      

      【讨论】:

        【解决方案14】:
                DefaultHttpClient httpclient = new DefaultHttpClient();
        
            SSLContext sslContext;
            try {
                sslContext = SSLContext.getInstance("SSL");
        
                // set up a TrustManager that trusts everything
                try {
                    sslContext.init(null,
                            new TrustManager[] { new X509TrustManager() {
                                public X509Certificate[] getAcceptedIssuers() {
                                    log.debug("getAcceptedIssuers =============");
                                    return null;
                                }
        
                                public void checkClientTrusted(
                                        X509Certificate[] certs, String authType) {
                                    log.debug("checkClientTrusted =============");
                                }
        
                                public void checkServerTrusted(
                                        X509Certificate[] certs, String authType) {
                                    log.debug("checkServerTrusted =============");
                                }
                            } }, new SecureRandom());
                } catch (KeyManagementException e) {
                }
                 SSLSocketFactory ssf = new SSLSocketFactory(sslContext,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                 ClientConnectionManager ccm = this.httpclient.getConnectionManager();
                 SchemeRegistry sr = ccm.getSchemeRegistry();
                 sr.register(new Scheme("https", 443, ssf));            
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            }
        

        【讨论】:

          【解决方案15】:

          要接受 HttpClient 4.4.x 中的所有证书,您可以在创建 httpClient 时使用以下一行:

          httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build()).build();
          

          【讨论】:

          • 我得到这个:原因:javax.net.ssl.SSLHandshakeException:java.security.cert.CertificateException:没有主题替代名称存在?
          • 如何在 HttpClient API 或 RestClient API 中允许连接到没有证书的 SSL 站点?
          【解决方案16】:

          以下代码适用于4.5.5

          import java.io.IOException;
          import java.security.KeyManagementException;
          import java.security.NoSuchAlgorithmException;
          import java.security.SecureRandom;
          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 org.apache.http.client.methods.CloseableHttpResponse;
          import org.apache.http.client.methods.HttpGet;
          import org.apache.http.client.methods.HttpUriRequest;
          import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
          import org.apache.http.impl.client.CloseableHttpClient;
          import org.apache.http.impl.client.HttpClients;
          import org.apache.http.util.EntityUtils;
          
          class HttpsSSLClient {
          
          
              public static CloseableHttpClient createSSLInsecureClient() {
                  SSLContext sslcontext = createSSLContext();
                  SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new HostnameVerifier() {
          
                      @Override
                      public boolean verify(String paramString, SSLSession paramSSLSession) {
                          return true;
                      }
                  });
                  CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
                  return httpclient;
              }
          
          
              private static SSLContext createSSLContext() {
                  SSLContext sslcontext = null;
                  try {
                      sslcontext = SSLContext.getInstance("TLS");
                      sslcontext.init(null, new TrustManager[] {new TrustAnyTrustManager()}, new SecureRandom());
                  } catch (NoSuchAlgorithmException e) {
                      e.printStackTrace();
                  } catch (KeyManagementException e) {
                      e.printStackTrace();
                  }
                  return sslcontext;
              }
          
          
              private static class TrustAnyTrustManager implements X509TrustManager {
          
                  public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
          
                  public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
          
                  public X509Certificate[] getAcceptedIssuers() {
                      return new X509Certificate[] {};
                  }
              }
          
          }
          public class TestMe {
          
          
              public static void main(String[] args) throws IOException {
                  CloseableHttpClient client = HttpsSSLClient.createSSLInsecureClient();
          
                  CloseableHttpResponse res = client.execute(new HttpGet("https://wrong.host.badssl.com/"));
                  System.out.println(EntityUtils.toString(res.getEntity()));
              }
          }
          

          代码的输出是

          浏览器的输出是

          使用的pom如下

          <?xml version="1.0" encoding="UTF-8"?>
          <project xmlns="http://maven.apache.org/POM/4.0.0"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
              <modelVersion>4.0.0</modelVersion>
          
              <groupId>com.tarun</groupId>
              <artifactId>testing</artifactId>
              <version>1.0-SNAPSHOT</version>
              <build>
                  <plugins>
                      <plugin>
                          <groupId>org.apache.maven.plugins</groupId>
                          <artifactId>maven-compiler-plugin</artifactId>
                          <configuration>
                              <source>6</source>
                              <target>6</target>
                          </configuration>
                      </plugin>
                  </plugins>
              </build>
          
              <dependencies>
              <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
              <dependency>
                  <groupId>org.apache.httpcomponents</groupId>
                  <artifactId>httpclient</artifactId>
                  <version>4.5.5</version>
              </dependency>
          
          </dependencies>
          </project>
          

          【讨论】:

            【解决方案17】:

            在 4.5.4 上测试:

                        SSLContext sslContext = new SSLContextBuilder()
                                .loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true).build();
            
                        CloseableHttpClient httpClient = HttpClients
                                .custom()
                                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                                .setSSLContext(sslContext)
                                .build();
            

            【讨论】:

              【解决方案18】:

              Apache HttpClient 4.1.3 的完整工作版本(基于上面 oleg 的代码,但我的系统上仍然需要一个 allow_all_hostname_verifier):

              private static HttpClient trustEveryoneSslHttpClient() {
                  try {
                      SchemeRegistry registry = new SchemeRegistry();
              
                      SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() {
              
                          public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
                              // Oh, I am easy...
                              return true;
                          }
              
                      }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
              
                      registry.register(new Scheme("https", 443, socketFactory));
                      ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
                      DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
                      return client;
                  } catch (GeneralSecurityException e) {
                      throw new RuntimeException(e);
                  }
              }
              

              请注意,我将重新抛出所有异常,因为实际上,如果在真实系统中出现任何故障,我无能为力!

              【讨论】:

                【解决方案19】:

                如果您使用fluent API,则需要通过Executor进行设置:

                Executor.unregisterScheme("https");
                SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext,
                                                  SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                Executor.registerScheme(new Scheme("https", 443, sslSocketFactory));
                

                ... 其中sslContext 是创建的 SSLContext,如 ZZ Coder 的答案所示。

                之后,您可以按照以下方式执行 http 请求:

                String responseAsString = Request.Get("https://192.168.1.0/whatever.json")
                                         .execute().getContent().asString();
                

                注意:使用 HttpClient 4.2 测试

                【讨论】:

                • 不幸的是,在 4.3 中已弃用:“已弃用。(4.3)请勿使用。”
                【解决方案20】:

                用 4.3.3 测试

                import java.security.KeyManagementException;
                import java.security.KeyStoreException;
                import java.security.NoSuchAlgorithmException;
                import java.security.SecureRandom;
                import java.security.cert.CertificateException;
                import java.security.cert.X509Certificate;
                
                import javax.net.ssl.SSLContext;
                
                import org.apache.http.Header;
                import org.apache.http.HttpEntity;
                import org.apache.http.client.methods.CloseableHttpResponse;
                import org.apache.http.client.methods.HttpGet;
                import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
                import org.apache.http.conn.ssl.SSLContexts;
                import org.apache.http.conn.ssl.TrustStrategy;
                import org.apache.http.impl.client.CloseableHttpClient;
                import org.apache.http.impl.client.HttpClients;
                import org.apache.http.util.EntityUtils;
                
                public class AccessProtectedResource {
                
                public static void main(String[] args) throws Exception {
                
                    // Trust all certs
                    SSLContext sslcontext = buildSSLContext();
                
                    // Allow TLSv1 protocol only
                    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                            sslcontext,
                            new String[] { "TLSv1" },
                            null,
                            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                
                    CloseableHttpClient httpclient = HttpClients.custom()
                            .setSSLSocketFactory(sslsf)
                            .build();
                    try {
                
                        HttpGet httpget = new HttpGet("https://yoururl");
                
                        System.out.println("executing request" + httpget.getRequestLine());
                
                        CloseableHttpResponse response = httpclient.execute(httpget);
                        try {
                            HttpEntity entity = response.getEntity();
                
                            System.out.println("----------------------------------------");
                            System.out.println(response.getStatusLine());
                            if (entity != null) {
                                System.out.println("Response content length: " + entity.getContentLength());
                            }
                            for (Header header : response.getAllHeaders()) {
                                System.out.println(header);
                            }
                            EntityUtils.consume(entity);
                        } finally {
                            response.close();
                        }
                    } finally {
                        httpclient.close();
                    }
                }
                
                private static SSLContext buildSSLContext()
                        throws NoSuchAlgorithmException, KeyManagementException,
                        KeyStoreException {
                    SSLContext sslcontext = SSLContexts.custom()
                            .setSecureRandom(new SecureRandom())
                            .loadTrustMaterial(null, new TrustStrategy() {
                
                                public boolean isTrusted(X509Certificate[] chain, String authType)
                                        throws CertificateException {
                                    return true;
                                }
                            })
                            .build();
                    return sslcontext;
                }
                

                }

                【讨论】:

                • 如果我想在 Headers 中设置值?
                【解决方案21】:

                如果您在使用嵌入 Apache HttpClient 4.1 的 AmazonS3Client 时遇到此问题,您只需要像这样定义一个系统属性,以便放松 SSL 证书检查器:

                -Dcom.amazonaws.sdk.disableCertChecking=true

                恶作剧管理

                【讨论】:

                  【解决方案22】:

                  fwiw,一个使用 JAX-RS 2.x 的“RestEasy”实现来构建一个特殊的“信任所有”客户端的示例......

                      import java.io.IOException;
                      import java.net.MalformedURLException;
                      import java.security.GeneralSecurityException;
                      import java.security.KeyManagementException;
                      import java.security.KeyStoreException;
                      import java.security.NoSuchAlgorithmException;
                      import java.security.cert.CertificateException;
                      import java.security.cert.X509Certificate;
                      import java.util.ArrayList;
                      import java.util.Arrays;
                      import javax.ejb.Stateless;
                      import javax.net.ssl.SSLContext;
                      import javax.ws.rs.GET;
                      import javax.ws.rs.Path;
                      import javax.ws.rs.Produces;
                      import org.apache.logging.log4j.LogManager;
                      import org.apache.logging.log4j.Logger;
                      import javax.ws.rs.client.Entity;
                      import javax.ws.rs.core.MediaType;
                      import javax.ws.rs.core.Response;
                      import org.apache.http.config.Registry;
                      import org.apache.http.config.RegistryBuilder;
                      import org.apache.http.conn.HttpClientConnectionManager;
                      import org.apache.http.conn.ssl.TrustStrategy;
                      import org.jboss.resteasy.client.jaxrs.ResteasyClient;
                      import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
                      import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
                      import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
                      import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
                      import org.apache.http.conn.socket.ConnectionSocketFactory;
                      import org.apache.http.conn.ssl.NoopHostnameVerifier;
                      import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
                      import org.apache.http.impl.client.CloseableHttpClient;
                      import org.apache.http.impl.client.HttpClientBuilder;
                      import org.apache.http.ssl.SSLContexts;
                  
                      @Stateless
                      @Path("/postservice")
                      public class PostService {
                  
                          private static final Logger LOG = LogManager.getLogger("PostService");
                  
                          public PostService() {
                          }
                  
                          @GET
                          @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
                          public PostRespDTO get() throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, GeneralSecurityException {
                  
                              //...object passed to the POST method...
                              PostDTO requestObject = new PostDTO();
                              requestObject.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C")));
                              requestObject.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));
                  
                              //...build special "trust all" client to call POST method...
                              ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(createTrustAllClient());
                  
                              ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
                              ResteasyWebTarget target = client.target("https://localhost:7002/postRespWS").path("postrespservice");
                              Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(requestObject, MediaType.APPLICATION_JSON));
                  
                              //...object returned from the POST method...
                              PostRespDTO responseObject = response.readEntity(PostRespDTO.class);
                  
                              response.close();
                  
                              return responseObject;
                          }
                  
                  
                          //...get special "trust all" client...
                          private static CloseableHttpClient createTrustAllClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
                  
                              SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, TRUSTALLCERTS).useProtocol("TLS").build();
                              HttpClientBuilder builder = HttpClientBuilder.create();
                              NoopHostnameVerifier noop = new NoopHostnameVerifier();
                              SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, noop);
                              builder.setSSLSocketFactory(sslConnectionSocketFactory);
                              Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build();
                              HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry);
                              builder.setConnectionManager(ccm);
                  
                              return builder.build();
                          }
                  
                  
                          private static final TrustStrategy TRUSTALLCERTS = new TrustStrategy() {
                              @Override
                              public boolean isTrusted(X509Certificate[] chain, String authType)
                                  throws CertificateException {
                                  return true;
                              }
                          };
                      }
                  

                  相关的 Maven 依赖项

                      <dependency>
                          <groupId>org.jboss.resteasy</groupId>
                          <artifactId>resteasy-client</artifactId>
                          <version>3.0.10.Final</version>
                      </dependency>
                      <dependency>
                          <groupId>org.jboss.resteasy</groupId>
                          <artifactId>jaxrs-api</artifactId>
                          <version>3.0.10.Final</version>
                      </dependency>
                      <dependency>
                          <groupId>org.jboss.resteasy</groupId>
                          <artifactId>resteasy-jackson2-provider</artifactId>
                          <version>3.0.10.Final</version>
                      </dependency>
                      <dependency>
                          <groupId>org.apache.httpcomponents</groupId>
                          <artifactId>httpclient</artifactId>
                          <version>4.5</version>
                          <type>jar</type>
                      </dependency>
                      <dependency>
                          <groupId>javax</groupId>
                          <artifactId>javaee-web-api</artifactId>
                          <version>7.0</version>
                          <scope>provided</scope>
                      </dependency> 
                  

                  【讨论】:

                    【解决方案23】:

                    如果您使用的是 Apache httpClient 4.5.x,请尝试以下操作:

                    public static void main(String... args)  {
                    
                        try (CloseableHttpClient httpclient = createAcceptSelfSignedCertificateClient()) {
                            HttpGet httpget = new HttpGet("https://example.com");
                            System.out.println("Executing request " + httpget.getRequestLine());
                    
                            httpclient.execute(httpget);
                            System.out.println("----------------------------------------");
                        } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    
                    private static CloseableHttpClient createAcceptSelfSignedCertificateClient()
                            throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
                    
                        // use the TrustSelfSignedStrategy to allow Self Signed Certificates
                        SSLContext sslContext = SSLContextBuilder
                                .create()
                                .loadTrustMaterial(new TrustSelfSignedStrategy())
                                .build();
                    
                        // we can optionally disable hostname verification. 
                        // if you don't want to further weaken the security, you don't have to include this.
                        HostnameVerifier allowAllHosts = new NoopHostnameVerifier();
                    
                        // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
                        // and allow all hosts verifier.
                        SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);
                    
                        // finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory
                        return HttpClients
                                .custom()
                                .setSSLSocketFactory(connectionFactory)
                                .build();
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-11-21
                      • 2013-10-31
                      • 2017-12-17
                      • 1970-01-01
                      • 2015-03-13
                      • 2019-09-05
                      • 1970-01-01
                      • 2015-04-22
                      相关资源
                      最近更新 更多