【问题标题】:How to get a simple Java client in eclipse to connect to a server using TLS1.2 protocol如何在 Eclipse 中获取一个简单的 Java 客户端以使用 TLS1.2 协议连接到服务器
【发布时间】:2016-01-05 18:16:08
【问题描述】:

我尝试了几种使用httpclient、urlconnection等访问rest服务的常用方法,但均无济于事。

我已经阅读了无数关于如何做到这一点的 Stack Overflow 文章,但在我的 eclipse mobilefirst/RSA 环境中没有任何作用。我正在使用 mobilefirst 7.1.1 和 RSA 9.1.1 运行 jdk 1.7。

根据我的阅读,您必须设置 SSLContext 才能与 tls1.2 服务器通信...因为相同的代码在其他服务器上也可以正常工作。我见过的只有一种方法可以让您设置 SSLContext,那就是使用ClientHTTPBuilder

这里有几个例子:

此示例适用于此 URL...但不适用于使用 tls1.2 的示例

URL url = new URL("https://wikipedia.org");
        URLConnection urlConnection = url.openConnection();
        InputStream in = urlConnection.getInputStream();
        str = getStringByBufferedReader(in);

第二个例子:

SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, null, null);
HttpClientBuilder clientBuilder = HttpClientBuilder.create().setSslcontext(context);
HttpGet request = new HttpGet(baseURL);
request.addHeader("Authorization", basicAuthorization);
request.addHeader("Accept", "text/plain");
CloseableHttpClient httpClient = clientBuilder.build();
CloseableHttpResponse httpResponse = httpClient.execute(request);

两种连接类型都出现以下错误:

Exception in Test method = javax.net.ssl.SSLException: Received fatal alert: protocol_version

我也导入了证书。我也试过 jdk 1.8 也无济于事。

【问题讨论】:

    标签: tls1.2


    【解决方案1】:

    JRE7 中的 TLS 解析为 TLSv1。将协议显式设置为 TLSv1.2:

    SSLContext context = SSLContext.getInstance("TLSv1.2");
    

    否则您使用HttpClientBuilder 的示例是可以的。

    编辑:

    如果你想禁用主机名检查(在生产系统中这是个坏主意):

    Apache httpclient

    package hello;
    
    import java.net.URI;
    
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.conn.scheme.Scheme;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLSocketFactory;
    import org.apache.http.impl.client.DefaultHttpClient;
    
    
    public class client {
    
        public static void main(String args[]) throws Exception {
    
    //      System.setProperty("javax.net.debug", "ssl:handshake:verbose");
    
            SSLSocketFactory socketFactory = null ;
    
            // Set benevolent host name verifier            
            socketFactory = new SSLSocketFactory( "TLS" , null /* Keystore*/ , 
                    null /* keystore passwd */ ,null /* trusts store */ , null , 
                    SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER ) ;
    
            Scheme sch = new Scheme("https", 443, socketFactory);
            DefaultHttpClient httpClient = new DefaultHttpClient() ;        
            httpClient.getConnectionManager().getSchemeRegistry().register(sch);        
    
            HttpGet request = new HttpGet(new URI("https://www.wikipedia.org/"));
    //        request.addHeader("Authorization", basicAuthorization);
    //        request.addHeader("Accept", "text/plain");
            CloseableHttpResponse httpResponse = httpClient.execute(request);
            System.out.println(httpResponse.getStatusLine());
    
            httpClient.close(); 
        }
    }
    

    使用Apache httpclient >= 4.3:

    package hello;
    
    import java.net.URI;
    import java.util.Arrays;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLParameters;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    
    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.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    
    import sun.security.ssl.SSLSocketFactoryImpl;
    
    public class client {
    
        public static void main(String args[]) throws Exception {
    
    //      System.setProperty("javax.net.debug", "ssl:handshake:verbose");
    
            SSLContext context = SSLContext.getInstance("TLSv1.2");
            context.init(null, null, null);
    
            SSLConnectionSocketFactory sslCF = new SSLConnectionSocketFactory(context, new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    // or add your own test here
                    return true;
                }
            });
    
            CloseableHttpClient httpClient = HttpClientBuilder
                    .create()
                    .setSSLSocketFactory(sslCF)
                    .build();
    
            HttpGet request = new HttpGet(new URI("https://www.wikipedia.org/"));
    //        request.addHeader("Authorization", basicAuthorization);
    //        request.addHeader("Accept", "text/plain");
            CloseableHttpResponse httpResponse = httpClient.execute(request);
            System.out.println(httpResponse.getStatusLine());           
        }
    }
    

    【讨论】:

    • javax.net.ssl.SSLProtocolException:握手警报:unrecognized_name
    • 我想现在我们要解决真正的问题了……这可能是证书问题吗?我从服务器导入的证书是自签名证书...不确定 TLS 1.2 是否允许这样做。我可以通过添加 --insecure 选项的 curl 使其工作。它也适用于 Chrome 和 Firefox 的各种 rest 客户端。
    • 添加 System.setProperty ("jsse.enableSNIExtension", "false"); ....现在出现此错误....javax.net.ssl.SSLPeerUnverifiedException:主机名“xxxx”与对等方提供的证书主题不匹配(EMAILADDRESS=xxx,CN=xxx,OU=SomeOrganizationalUnit,O= SomeOrganization, L=SomeCity, ST=SomeState, C=--)
    • 这意味着您正在通过与服务器证书中所述的域名不同的域名访问服务器。快速解决方法:将证书中的域名添加到“主机”文件和服务器实际 IP 中。另一种解决方案是在 Java 中禁用主机名检查。
    【解决方案2】:

    我可以在主类中用一行来修复它:

     System.setProperty("https.protocols", "SSLv3,TLSv1,TLSv1.1,TLSv1.2");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-21
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      相关资源
      最近更新 更多