Android的HTTPS的业务通信(SSL / TLS 1.2) [英] Android Https web service communication (SSL / TLS 1.2)

查看:2753
本文介绍了Android的HTTPS的业务通信(SSL / TLS 1.2)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Andr​​oid应用程序,我已经有了一个HTTPS Web服务通信和读取响应。

我已经通知服务器中配置的 SSL TLS 1.2

我使用下面的示例code与服务连接(HTTPS GET请求),但只在运行设备的的是Android 5.0 或以上可以成功地沟通和读取响应.. ..

试图建立连接时,所有的版本低于其它装置(Android 5.0)无法沟通,当时抛出IOException异常...

 的Htt presponse响应= NULL;
    尝试
    {
        HttpClient的客户端=新DefaultHttpClient();        HTTPGET请求=新HTTPGET();
        request.setURI(新的URI(https://domain.co.uk/services/pay.aspx?param1=val1&param2=val2));        响应= client.execute(请求);        HttpEntity实体= response.getEntity();
        字符串responseString = EntityUtils.toString(实体);
        字符串德codedResStr = URLDe coder.de code(responseString,UTF-8);        Log.v(届时AppState,回应:C $ cdResStr +的$);
    }
    赶上(例外五)
    {
        e.printStackTrace();
        Log.v(届时AppState,异常:+ e.getMessage())
    }

  // HttpURLConnection类的URLConnection = NULL;
    HttpsURLConnection的URLConnection的= NULL;    尝试
    {
        网址URL =新的URL(https://domain.co.uk/services/pay.aspx?param1=val1&param2=val2);
        //的URLConnection =(HttpURLConnection类)url.openConnection();
        URLConnection的=(HttpsURLConnection的)url.openConnection();        在的InputStream =新的BufferedInputStream(urlConnection.getInputStream());    }
    赶上(例外五)
    {
        e.printStackTrace();
        Log.v(届时AppState,异常:+ e.getMessage())
    }
    最后
    {
        urlConnection.disconnect();
    }

问题1

想知道如果我在这里做错什么(如果有额外的参数在我的code丢失,将支持旧版本的机器人比5.0的支持TLS 1.2的Web服务通信)?

问题2

我只是用Google搜索,发现这个 DOCUMENT

有它说,最小值出现在ANDROID支持浏览器1.2 TLS沟通是谷歌Android 5.0操作系统的浏览器。因此,它是相同限制应用试图用code(应用程序)连接时?

如果这样,这将是最小的Andr​​oid版本我应该支持,如果要与此Web服务(机器人的最低版本支持TLS 1.2的Web服务)进行通信?

样品异常堆栈跟踪如下所示

Android 2.2的模拟器

  12月11日至6日:51:01.885:W / System.err的(352):java.io.IOException异常:SSL握手失败:I / O错误系统调用过程中,未知错误:0
    12月11日至6日:51:01.895:W / System.err的(352):在org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.nativeconnect(本机方法)
    12月11日至6日:51:01.895:W / System.err的(352):在org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:316)
    12月11日至6日:51:01.895:W / System.err的(352):在org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168)
    12月11日至6日:51:01.905:W / System.err的(352):在org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:399)
    12月11日至6日:51:01.915:W / System.err的(352):在org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1152)
    12月11日至6日:51:01.915:W / System.err的(352):在org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:253)
    12月11日至6日:51:01.915:W / System.err的(352):在com.serviceapp.WSHelperHttpURLConnection.executeAndroid(WSHelperHttpURLConnection.java:93)
    12月11日至6日:51:01.915:W / System.err的(352):在com.serviceapp.HttpPage $ 1 $ 1.run(HttpPage.java:69)
    12月11日至6日:51:01.915:W / System.err的(352):在java.lang.Thread.run(Thread.java:1096)

Android 3.0的模拟器

  12月11日至6日:56:22.917:W / System.err的(447):javax.net.ssl​​.SSLException:连接被关闭同行
12月11日至6日:56:22.927:W / System.err的(447):在org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(本机方法)
12月11日至6日:56:22.927:W / System.err的(447):在org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:485)
12月11日至6日:56:22.927:W / System.err的(447):在org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:323)
12月11日至6日:56:22.927:W / System.err的(447):在org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.setupSecureSocket(HttpConnection.java:167)
12月11日至6日:56:22.937:W / System.err的(447):在org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:479)
12月11日至6日:56:22.937:W / System.err的(447):在org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeConnection(HttpsURLConnectionImpl.java:428)
12月11日至6日:56:22.937:W / System.err的(447):在org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1038)
12月11日至6日:56:22.937:W / System.err的(447):在org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:523)
12月11日至6日:56:22.937:W / System.err的(447):在org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:283)
12月11日至6日:56:22.947:W / System.err的(447):在com.serviceapp.WSHelperHttpURLConnection.executeAndroid(WSHelperHttpURLConnection.java:93)
12月11日至6日:56:22.947:W / System.err的(447):在com.serviceapp.HttpPage $ 1 $ 1.run(HttpPage.java:69)
12月11日至6日:56:22.947:W / System.err的(447):在java.lang.Thread.run(Thread.java:1020)

EDITS

这是完整的堆栈跟踪时使用罗伯特MySSLSocketFactory级FPGA实现用的是Android 4.4.2和Android 5.1.1的设备。

  11-06 14:26:46.962:W / System.err的(14700):java.lang.IllegalArgumentException异常:协议TLS1.2不支持
11-06 14:26:46.985:W / System.err的(14700):在com.android.org.conscrypt.NativeCrypto.checkEnabledProtocols(NativeCrypto.java:879)
11-06 14:26:46.985:W / System.err的(14700):在com.android.org.conscrypt.OpenSSLSocketImpl.setEnabledProtocols(OpenSSLSocketImpl.java:807)
11-06 14:26:46.985:W / System.err的(14700):在com.serviceapp.MySSLSocketFactory.createSocket(WSURlCon.java:99)
11-06 14:26:46.986:W / System.err的(14700):在com.serviceapp.MySSLSocketFactory.createSocket(WSURlCon.java:1)
11-06 14:26:46.986:W / System.err的(14700):在com.android.okhttp.Connection.upgradeToTls(Connection.java:131)
11-06 14:26:46.986:W / System.err的(14700):在com.android.okhttp.Connection.connect(Connection.java:107)
11-06 14:26:46.986:W / System.err的(14700):在com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
11-06 14:26:46.987:W / System.err的(14700):在com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
11-06 14:26:46.988:W / System.err的(14700):在com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
11-06 14:26:46.988:W / System.err的(14700):在com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
11-06 14:26:46.990:W / System.err的(14700):在com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
11-06 14:26:46.990:W / System.err的(14700):在com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:179)
11-06 14:26:46.991:W / System.err的(14700):在com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:246)
11-06 14:26:46.991:W / System.err的(14700):在com.serviceapp.WSURlCon.executeAndroid(WSURlCon.java:33)
11-06 14:26:46.992:W / System.err的(14700):在com.serviceapp.HttpPage $ 1 $ 1.run(HttpPage.java:74)
11-06 14:26:46.992:W / System.err的(14700):在java.lang.Thread.run(Thread.java:848)


解决方案

据Android开发者文档TLS 1.2是提供与API级别的设备启用20+(Android 4.4的耐磨):

http://developer.android.com/reference/javax/净/ SSL / SSLEngine.html

我假设你的测试设备不使用该API的级别,因此你得到了,只有5.0的设备可以连接的结果。

我个人的体会是,但不启用它的一些4.4系统的设备支持TLS 1.2。您可以尝试通过调用来启用它 setEnabledProtocols(新的String [] {TLSv1.2工作})所用的SSLSocket。

这是优雅的解决方案这样使用代理模式正在实施自己的SSLSocketFactory的:

 公共类MySSLSocketFactory扩展的SSLSocketFactory {    SSLSocketFactory的SSLSocketFactory的;    公共MySSLSocketFactory(SSLSocketFactory的的SSLSocketFactory){
        超();
        this.sslSocketFactory = SSLSocketFactory的;
    }    @覆盖
    公众的String [] getDefaultCipherSuites(){
        返回sslSocketFactory.getDefaultCipherSuites();
    }    @覆盖
    公众的String [] getSupportedCipherSuites(){
        返回sslSocketFactory.getSupportedCipherSuites();
    }    @覆盖
    公众的SSLSocket的createSocket(插座S,字符串主机,端口INT,布尔自动关闭)抛出IOException
        SSLSocket的插座=(SSLSocket的)sslSocketFactory.createSocket(S,主机,端口自动关闭);
        socket.setEnabledProtocols(新的String [] {TLSv1.2工作});
        返回插座;
    }    @覆盖
    公共插座的createSocket(字符串主机,诠释端口)抛出IOException异常,{UnknownHostException异常
        SSLSocket的插座=(SSLSocket的)sslSocketFactory.createSocket(主机,端口);
        socket.setEnabledProtocols(新的String [] {TLSv1.2工作});
        返回插座;
    }    @覆盖
    公共插座的createSocket(字符串主机,诠释端口,本地主机的InetAddress,INT将localPort)抛出IOException异常,
            {的UnknownHostException
        SSLSocket的插座=(SSLSocket的)sslSocketFactory.createSocket(主机,端口,本地主机,将localPort);
        socket.setEnabledProtocols(新的String [] {TLSv1.2工作});
        返回插座;
    }    @覆盖
    公共插座的createSocket(InetAddress的主机,诠释端口)抛出IOException
        SSLSocket的插座=(SSLSocket的)sslSocketFactory.createSocket(主机,端口);
        socket.setEnabledProtocols(新的String [] {TLSv1.2工作});
        返回插座;
    }    @覆盖
    公共插座的createSocket(InetAddress类地址,端口INT,InetAddress类将localAddress,INT将localPort)
            抛出IOException
        SSLSocket的插座=(SSLSocket的)sslSocketFactory.createSocket(地址,端口,将localAddress,将localPort);
        socket.setEnabledProtocols(新的String [] {TLSv1.2工作});
        返回插座;
    }

您可以用这种方式:

  ...
    URLConnection的=(HttpsURLConnection的)url.openConnection();
    urlConnection.setSSLSocketFactory(新MySSLSocketFactory(urlConnection.getSSLSocketFactory()));
    ...

In my Android application I've got to communicate with a https web service and read the response.

I've informed the server configured SSL with TLS 1.2.

I am using the following sample code to connect with the service (https get request), but only the devices that runs Android 5.0 or above can successfully communicate and read the response....

All the other devices below that version (Android 5.0) can't communicate and thrown IOException at the time when trying to establish connection...

    HttpResponse response = null;
    try 
    {        
        HttpClient client = new DefaultHttpClient();

        HttpGet request = new HttpGet();
        request.setURI(new URI("https://domain.co.uk/services/pay.aspx?param1=val1&param2=val2"));

        response = client.execute(request);

        HttpEntity entity = response.getEntity();
        String responseString = EntityUtils.toString(entity); 
        String decodedResStr = URLDecoder.decode(responseString, "UTF-8");  

        Log.v("AppState", "Response: " + decodedResStr);
    }  
    catch (Exception e) 
    {
        e.printStackTrace();
        Log.v("AppState", "Exception: " + e.getMessage() )
    }

OR

    // HttpURLConnection urlConnection = null;
    HttpsURLConnection urlConnection = null;

    try
    {
        URL url = new URL("https://domain.co.uk/services/pay.aspx?param1=val1&param2=val2");
        //urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection = (HttpsURLConnection) url.openConnection();

        InputStream in = new BufferedInputStream(urlConnection.getInputStream());

    }
    catch (Exception e)
    {
        e.printStackTrace();
        Log.v("AppState", "Exception: " + e.getMessage() )
    }
    finally
    {
        urlConnection.disconnect();
    }

Question 1

Would like to know if I am doing anything wrong in here (if any additional parameter is missing in my code that will support older versions of Androids than 5.0 to support TLS 1.2 web service communication) ?

Question 2

I just googled and found this DOCUMENT.

There it says the minimum supporting browser in ANDROID to communicate with TLS 1.2 is "GOOGLE Android 5.0 OS Browser". So is it the same restriction applying when trying to connect by the code (Apps)?

if so what would be the minimum Android version I should support if want to communicate with this web service (the minimum version of android that support TLS 1.2 web services)?

Sample exception stack traces are as follows

Android 2.2 Simulator

    11-06 12:51:01.885: W/System.err(352): java.io.IOException: SSL handshake failure: I/O error during system call, Unknown error: 0
    11-06 12:51:01.895: W/System.err(352):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.nativeconnect(Native Method)
    11-06 12:51:01.895: W/System.err(352):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:316)
    11-06 12:51:01.895: W/System.err(352):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168)
    11-06 12:51:01.905: W/System.err(352):  at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:399)
    11-06 12:51:01.915: W/System.err(352):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1152)
    11-06 12:51:01.915: W/System.err(352):  at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:253)
    11-06 12:51:01.915: W/System.err(352):  at com.serviceapp.WSHelperHttpURLConnection.executeAndroid(WSHelperHttpURLConnection.java:93)
    11-06 12:51:01.915: W/System.err(352):  at com.serviceapp.HttpPage$1$1.run(HttpPage.java:69)
    11-06 12:51:01.915: W/System.err(352):  at java.lang.Thread.run(Thread.java:1096)

Android 3.0 Simulator

11-06 12:56:22.917: W/System.err(447): javax.net.ssl.SSLException: Connection closed by peer
11-06 12:56:22.927: W/System.err(447):  at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
11-06 12:56:22.927: W/System.err(447):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:485)
11-06 12:56:22.927: W/System.err(447):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:323)
11-06 12:56:22.927: W/System.err(447):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.setupSecureSocket(HttpConnection.java:167)
11-06 12:56:22.937: W/System.err(447):  at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:479)
11-06 12:56:22.937: W/System.err(447):  at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeConnection(HttpsURLConnectionImpl.java:428)
11-06 12:56:22.937: W/System.err(447):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1038)
11-06 12:56:22.937: W/System.err(447):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:523)
11-06 12:56:22.937: W/System.err(447):  at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:283)
11-06 12:56:22.947: W/System.err(447):  at com.serviceapp.WSHelperHttpURLConnection.executeAndroid(WSHelperHttpURLConnection.java:93)
11-06 12:56:22.947: W/System.err(447):  at com.serviceapp.HttpPage$1$1.run(HttpPage.java:69)
11-06 12:56:22.947: W/System.err(447):  at java.lang.Thread.run(Thread.java:1020)

EDITS

This is the full stack trace when use Robert's MySSLSocketFactory class implemention with an Android 4.4.2 AND Android 5.1.1 device.

11-06 14:26:46.962: W/System.err(14700): java.lang.IllegalArgumentException: protocol TLS1.2 is not supported
11-06 14:26:46.985: W/System.err(14700):    at com.android.org.conscrypt.NativeCrypto.checkEnabledProtocols(NativeCrypto.java:879)
11-06 14:26:46.985: W/System.err(14700):    at com.android.org.conscrypt.OpenSSLSocketImpl.setEnabledProtocols(OpenSSLSocketImpl.java:807)
11-06 14:26:46.985: W/System.err(14700):    at com.serviceapp.MySSLSocketFactory.createSocket(WSURlCon.java:99)
11-06 14:26:46.986: W/System.err(14700):    at com.serviceapp.MySSLSocketFactory.createSocket(WSURlCon.java:1)
11-06 14:26:46.986: W/System.err(14700):    at com.android.okhttp.Connection.upgradeToTls(Connection.java:131)
11-06 14:26:46.986: W/System.err(14700):    at com.android.okhttp.Connection.connect(Connection.java:107)
11-06 14:26:46.986: W/System.err(14700):    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
11-06 14:26:46.987: W/System.err(14700):    at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
11-06 14:26:46.988: W/System.err(14700):    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
11-06 14:26:46.988: W/System.err(14700):    at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
11-06 14:26:46.990: W/System.err(14700):    at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
11-06 14:26:46.990: W/System.err(14700):    at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:179)
11-06 14:26:46.991: W/System.err(14700):    at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:246)
11-06 14:26:46.991: W/System.err(14700):    at com.serviceapp.WSURlCon.executeAndroid(WSURlCon.java:33)
11-06 14:26:46.992: W/System.err(14700):    at com.serviceapp.HttpPage$1$1.run(HttpPage.java:74)
11-06 14:26:46.992: W/System.err(14700):    at java.lang.Thread.run(Thread.java:848)

解决方案

According to the Android Developer documentation TLS 1.2 is available and enabled on devices with API level 20+ (Android 4.4 Wearable):

http://developer.android.com/reference/javax/net/ssl/SSLEngine.html

I assume non of your test devices uses that API level therefore you got the result that only 5.0 devices can connect.

My personal experience is that some 4.4 devices support TLS 1.2 however it is not enabled. You can try to enable it by calling setEnabledProtocols(new String[]{"TLSv1.2"}) on the used SSLSocket.

An elegant solution doing so is implementing an own SSLSocketFactory using the Proxy pattern:

public class MySSLSocketFactory extends SSLSocketFactory {

    SSLSocketFactory sslSocketFactory;

    public MySSLSocketFactory(SSLSocketFactory sslSocketFactory) {
        super();
        this.sslSocketFactory = sslSocketFactory;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return sslSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return sslSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(s, host, port, autoClose);
        socket.setEnabledProtocols(new String[] { "TLSv1.2" });
        return socket;
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(host, port);
        socket.setEnabledProtocols(new String[] { "TLSv1.2" });
        return socket;
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException,
            UnknownHostException {
        SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(host, port, localHost, localPort);
        socket.setEnabledProtocols(new String[] { "TLSv1.2" });
        return socket;
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(host, port);
        socket.setEnabledProtocols(new String[] { "TLSv1.2" });
        return socket;
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
            throws IOException {
        SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address, port, localAddress, localPort);
        socket.setEnabledProtocols(new String[] { "TLSv1.2" });
        return socket;
    }

You can use it this way:

    ...
    urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.setSSLSocketFactory(new MySSLSocketFactory(urlConnection.getSSLSocketFactory()));
    ...

这篇关于Android的HTTPS的业务通信(SSL / TLS 1.2)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆