【问题标题】:Spring Rest Template : Host name 'localhost' does not match the certificate subject provided by the peerSpring Rest 模板:主机名“localhost”与对等方提供的证书主题不匹配
【发布时间】:2016-10-19 04:25:38
【问题描述】:

我像这样使用 RestTemplate 配置:

private RestTemplate createRestTemplate() throws Exception {
        final String username = "admin";
        final String password = "admin";
        final String proxyUrl = "localhost";
        final int port = 443;

        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(new AuthScope(proxyUrl, port),
                new UsernamePasswordCredentials(username, password));

        HttpHost host = new HttpHost(proxyUrl, port, "https");

        HttpClientBuilder clientBuilder = HttpClientBuilder.create();

        clientBuilder.setProxy(host).setDefaultCredentialsProvider(credsProvider).disableCookieManagement();

        HttpClient httpClient = clientBuilder.build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);

        return new RestTemplate(factory);
    }

这就是我的方法的工作原理:

public String receiveMessage(String message) {
        try {
            restTemplate = createRestTemplate();
            ObjectMapper mapper = new ObjectMapper();
            Class1 class1 = null;
            String json2 = "";

            class1= mapper.readValue(message, Class1.class);

            Class1 class2 = restTemplate.getForObject(URL_SERVICE_1 + "/class1/findByName?name=" + class1.getName(),
                    Class1.class);
            System.out.println("Server 1 : " + message);
            json2 = mapper.writeValueAsString(class2);

            return "Error - " + json2;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            return e.getMessage();
        }

    }

URL_SERVICE_1 包含https://localhost

当我尝试调用函数 GET 时,我总是得到这样的返回:

I/O error on GET request for "https://localhost/class1/findByName?name=20-1P": Host name 'localhost' does not match the certificate subject provided by the peer (CN=*.webku-cool.com, OU=EssentialSSL Wildcard, OU=Domain Control Validated); nested exception is javax.net.ssl.SSLPeerUnverifiedException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=*.webku-cool.com, OU=EssentialSSL Wildcard, OU=Domain Control Validated)

我不知道使用 https 的 restTemplate 的正确设置。我已经尝试了 23 次关于 SSL 设置的参考,并得到了同样的错误。

1. Reference

2. Reference

3. Reference

【问题讨论】:

    标签: java spring ssl resttemplate


    【解决方案1】:

    由于已接受的答案已弃用代码,这对我很有帮助:

    SSLContextBuilder sslcontext = new SSLContextBuilder();
                sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());
                httpclient = HttpAsyncClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                        .build();
    

    【讨论】:

      【解决方案2】:

      此问题的正确解决方案是通过将 localhost 添加到主题列表来更正 ssl 证书。但是,如果您的意图是为了开发目的而绕过 ssl,则需要定义一个连接工厂,它始终将主机名验证的结果返回为 true。

      SSLClientHttpRequestFactory

      public class SSLClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
      
          @Override
          protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
              try {
                  if (!(connection instanceof HttpsURLConnection)) {
                      throw new RuntimeException("An instance of HttpsURLConnection is expected");
                  }
      
                  HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
      
                  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 sslContext = SSLContext.getInstance("TLS");
                  sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                  httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));
      
                  httpsConnection.setHostnameVerifier(new HostnameVerifier() {
                      public boolean verify(String hostname, SSLSession session) {
                          return true;
                      }
                  });
      
                  super.prepareConnection(httpsConnection, httpMethod);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          /**
           * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"});
           * see
           * http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566
           * -2342133.html (Java 8 section)
           */
          private static class MyCustomSSLSocketFactory extends SSLSocketFactory {
      
              private final SSLSocketFactory delegate;
      
              public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
                  this.delegate = delegate;
              }
      
              @Override
              public String[] getDefaultCipherSuites() {
                  return delegate.getDefaultCipherSuites();
              }
      
              @Override
              public String[] getSupportedCipherSuites() {
                  return delegate.getSupportedCipherSuites();
              }
      
              @Override
              public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose)
                      throws IOException {
                  final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
                  return overrideProtocol(underlyingSocket);
              }
      
              @Override
              public Socket createSocket(final String host, final int port) throws IOException {
                  final Socket underlyingSocket = delegate.createSocket(host, port);
                  return overrideProtocol(underlyingSocket);
              }
      
              @Override
              public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                      final int localPort) throws IOException {
                  final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
                  return overrideProtocol(underlyingSocket);
              }
      
              @Override
              public Socket createSocket(final InetAddress host, final int port) throws IOException {
                  final Socket underlyingSocket = delegate.createSocket(host, port);
                  return overrideProtocol(underlyingSocket);
              }
      
              @Override
              public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
                      final int localPort) throws IOException {
                  final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
                  return overrideProtocol(underlyingSocket);
              }
      
              private Socket overrideProtocol(final Socket socket) {
                  if (!(socket instanceof SSLSocket)) {
                      throw new RuntimeException("An instance of SSLSocket is expected");
                  }
                  ((SSLSocket) socket).setEnabledProtocols(new String[] { "TLSv1" });
                  return socket;
              }
          }
      }

      并使用上面提到的连接工厂作为 RestTemplate 的构造函数参数。覆盖主机名验证以始终返回 true 的部分代码如下:

      httpsConnection.setHostnameVerifier(new HostnameVerifier() {
                      public boolean verify(String hostname, SSLSession session) {
                          return true;
                      }
                  });
      

      编码愉快!

      【讨论】:

      • 您无法在 2015 年 11 月 1 日之后从公共 CA(包括 Comodo)获得 localhost 的证书。根据网络服务器,另一种可能性是在 URL 中使用正确的名称,可能是test.webku-cool.com 或者可能是 SAN 中未显示在 Q 中的值,并设置系统的名称解析(通常是主机文件或本地/代理 DNS,但也可能是其他)以将该名称映射到 127.0.0.1。跨度>
      【解决方案3】:

      这是我如何让它工作的: 1.这个bean忽略SSL检查 2. 它也忽略证书不匹配

      @Bean
          public RestTemplate restTemplate()
                  throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
              TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
      
              SSLContextBuilder sslcontext = new SSLContextBuilder();
              sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());
      
              SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                                                                     .loadTrustMaterial(null, acceptingTrustStrategy)
                                                                     .build();
      
              SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
      
              CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(
                      NoopHostnameVerifier.INSTANCE)
                                                          .build();
      
              HttpComponentsClientHttpRequestFactory requestFactory =
                      new HttpComponentsClientHttpRequestFactory();
      
              requestFactory.setHttpClient(httpClient);
              RestTemplate restTemplate = new RestTemplate(requestFactory);
              return restTemplate;
          }
      

      【讨论】:

        【解决方案4】:

        在网上尝试了很多不同的选项后,这个选项对我有用...非常感谢...

        SSLContextBuilder sslcontext = new SSLContextBuilder();
                    sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());
        HttpClient httpClient = HttpAsyncClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                        .build();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-12-27
          • 2019-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多