2015-11-06 180 views
3

在我的Android應用程序中,我必須與https Web服務進行通信並閱讀響應。Android Https Web服務通信(SSL/TLS 1.2)

我已通知配置的服務器SSLTLS 1.2

我使用下面的示例代碼與運行的Android 5.0或以上可以成功地通信,並讀取響應服務(HTTPS GET請求),但只有設備連接....

所有試圖建立連接時,該版本低於其它裝置(Android 5.0)無法溝通,當時拋出IOException異常......

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(); 
    } 

問題1

想知道如果我在這裏做錯什麼(如果有額外的參數,在我的代碼丟失,將支持舊版本的機器人會比5.0的支持TLS 1.2的Web服務溝通)?

問題2

我只是用Google搜索,發現這個DOCUMENT

那裏它說ANDROID與TLS 1.2溝通的最低支持瀏覽器是「GOOGLE Android 5.0 OS瀏覽器」。那麼當試圖通過代碼(應用程序)進行連接時,是否應用相同的限制?

如果是這樣,如果要與此Web服務(支持TLS 1.2 Web服務的Android的最低版本)進行通信,我應該支持哪些最低Android版本?

樣品異常堆棧跡線是如下

的Android 2.2模擬器

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的模擬器

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

這是一個完整的堆棧跟蹤時使用羅伯特MySSLSocketFactory類用FPGA實現的是Android 4.4.2和Android 5.1.1設備。

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) 

回答

5

根據Android開發者文檔,TLS 1.2可用於API級別爲20+(Android 4)的設備。4耐磨):

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

我假設你的測試設備不使用該API級別,因此你得只有5.0設備可以連接的結果。

我個人的經驗是,一些4.4設備支持TLS 1.2,但它沒有啓用。您可以嘗試通過在使用的SSLSocket上調用setEnabledProtocols(new String[]{"TLSv1.2"})來啓用它。

優雅的解決方案這樣做是使用代理模式實現了自己的SSLSocketFactory:

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; 
    } 

你可以用這種方式:

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

嗨羅伯特,感謝您的回答。我剛剛使用運行Android版本4.4.2的Android設備定義的「MySSLSocketFactory」類進行了測試,並獲取異常消息「java.lang.IllegalArgumentException:protocol TLS1.2 is not supported」。我將在我的問題編輯中添加完整的堆棧跟蹤....另外作爲一個輔助測試,設備默認的web瀏覽器(chrome和android網絡瀏覽器都可以)訪問web服務託管的url沒有任何問題。 – JibW

+0

也是Android 5.1.1設備的例外。 – JibW

+0

看起來我錯過了'v':正確的應該是''TLSv1.2'' – Robert