【问题标题】:HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated when time shifted?HttpClient javax.net.ssl.SSLPeerUnverifiedException:时移时对等方未通过身份验证?
【发布时间】:2014-07-15 07:37:39
【问题描述】:

由于要求,我们需要通过将系统日期转移到未来的日期,如 2025-05-05 来测试 https 连接,问题是使用HttpClient(版本 4.2)时,会遇到异常 javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

简单代码段如下:

@Test
public void httpsShouldWorking() throws Exception {

    HttpClient client = new DefaultHttpClient();

    String urlOverHttps = "https://URL";
    HttpGet getMethod = new HttpGet(urlOverHttps);
    HttpResponse response = client.execute(getMethod);

    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
}

我也google了一下,找到了解决办法HttpClient with SSL

如前所述:

现在让我们将 http 客户端配置为信任所有证书链,无论其有效性如何:

但是在尝试之后,它不起作用并且仍然得到身份验证异常。

有没有办法在系统日期偏移时避免验证?

【问题讨论】:

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


    【解决方案1】:

    可以让 HttpClient 绕过 SSL 证书有效性的检查。这段代码可以用来获取HttpClient的一个实例:

    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import java.security.SecureRandom;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    ......
    private static HttpClient getHttpClient() {
    
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
    
            sslContext.init(null,
                    new TrustManager[]{new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
    
                            return null;
                        }
    
                        public void checkClientTrusted(
                                X509Certificate[] certs, String authType) {
    
                        }
    
                        public void checkServerTrusted(
                                X509Certificate[] certs, String authType) {
    
                        }
                    }}, new SecureRandom());
    
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
    
    
            HttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
    
            return httpClient;
    
        } catch (Exception e) {
            e.printStackTrace();
            return HttpClientBuilder.create().build();
        }
    }
    

    不再抛出异常,当证书过期时,浏览器会发出证书过期警告并让用户确认。

    【讨论】:

    • httpClient = HttpClientBuilder.create() .setSSLSocketFactory(socketFactory).build();.我在这里遇到了一些错误。错误是:线程“main”中的异常 java.lang.NoSuchFieldError: INSTANCE
    • 在 org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:52) 在 org.apache.http.impl.io.DefaultHttpRequestWriterFactory。 <init>(DefaultHttpRequestWriterFactory.java:56) 在 org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<clinit>(DefaultHttpRequestWriterFactory.java:46) 在 org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>( ManagedHttpClientConnectionFactory.java:72) 在 org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:84)</init></init></clinit></init></init>
    • 对于 HttpClient 3.x 而不是 SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) 使用 org.jsslutils.extra.apachehttpclient.SslContextedSecureProtocolSocketFactory(sslContext, false)
    【解决方案2】:
    public static HttpClient verifiedClient(HttpClient base) {  
        try {  
            SSLContext ctx = SSLContext.getInstance("SSL");  
            X509TrustManager tm = new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
                    return null;  
                }  
                @Override  
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}  
                @Override  
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}  
            };
    
            ctx.init(null, new TrustManager[] { tm }, null); 
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
            ClientConnectionManager mgr = base.getConnectionManager();
            SchemeRegistry registry = mgr.getSchemeRegistry(); 
            registry.register(new Scheme("https", 443, ssf)); 
            return new DefaultHttpClient(mgr, base.getParams());  
        } catch (Exception ex) {  
            ex.printStackTrace();  
            return null;  
        }  
    }  
    

    【讨论】:

    • 您能否详细说明您的答案,添加更多关于您提供的解决方案的描述?
    • 我必须使用SSLContext ctx = SSLContext.getInstance("TLSv1.2");(而不是“SSL”)。
    【解决方案3】:

    与其禁用整个安全链,不如将特定证书导入 JAVA 安装的密钥库。如何做到这一点,你可以在这里找到:http://java67.blogspot.co.at/2012/09/keytool-command-examples-java-add-view-certificate-ssl.html

    【讨论】:

      【解决方案4】:

      看了很多回答,this was the one that helped me

      我通过忽略一些 TLS 算法解决了我的问题。

      编辑文件:$JAVA_HOME/jre/lib/security/java.security

      通过将这两个算法附加到jdk.tls.disabledAlgorithms,将它们添加到列表DHE, ECDHE

      所以,就我而言,最终结果是:

      jdk.tls.disabledAlgorithms=SSLv3, DHE, ECDHE

      【讨论】:

        【解决方案5】:

        就我而言,在以下情况下:

        • JDK8
        • 从 Junit 测试运行
        • 使用 resteasy-client

        以下参数起作用:

        -Djdk.tls.client.protocols=TLSv1
        

        欲了解更多信息,请查看:
        https://www.java.com/en/configure_crypto.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-30
          • 1970-01-01
          相关资源
          最近更新 更多