在我的Android应用程序中,我必须与https网络服务进行通信并阅读回复。
我已通过 TLS 1.2 通知配置 SSL 的服务器。
我使用以下示例代码连接服务(https get request),但只有运行 Android 5.0 或更高版本的设备才能成功通信并阅读响应.... / p>
该版本(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¶m2=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() )
}
或
// HttpURLConnection urlConnection = null;
HttpsURLConnection urlConnection = null;
try
{
URL url = new URL("https://domain.co.uk/services/pay.aspx?param1=val1¶m2=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
想知道我在这里做错了什么(如果我的代码中缺少任何附加参数,支持旧版本的Androids而不是5.0以支持TLS 1.2 Web服务通信)?
问题2
我只是用谷歌搜索,发现了DOCUMENT。
在那里它表示ANDROID中与TLS 1.2通信的最低支持浏览器是" GOOGLE Android 5.0 OS浏览器"。那么在尝试通过代码(Apps)进行连接时是否也适用相同的限制?
如果是这样,如果想与这个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
使用Robert的MySSLSocketFactory类实现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)
答案 0 :(得分:9)
根据Android Developer文档,在API级别为20+(Android 4.4可穿戴设备)的设备上可以使用并启用TLS 1.2:
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()));
...
答案 1 :(得分:0)
以下是罗伯特(Robert)回答的科特林版本,它解决了我的问题:
import java.net.InetAddress
import java.net.Socket
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
class MySSLSocketFactory(socket_factory :SSLSocketFactory):
SSLSocketFactory()
{
val sslSocketFactory :SSLSocketFactory
init
{
this.sslSocketFactory = socket_factory
}
override fun getDefaultCipherSuites(): Array<String>
{
return this.sslSocketFactory.getDefaultCipherSuites()
}
override fun createSocket(socket: Socket?, host: String?, port: Int, autoclose: Boolean): Socket
{
val socket: SSLSocket = this.sslSocketFactory.createSocket(socket, host, port, autoclose) as SSLSocket
socket.setEnabledProtocols(arrayOf("TLSv1.2"))
return socket
}
override fun createSocket(host: String?, port: Int): Socket
{
val socket: SSLSocket = this.sslSocketFactory.createSocket(host, port) as SSLSocket
socket.setEnabledProtocols(arrayOf("TLSv1.2"))
return socket
}
override fun createSocket(host: String?, port: Int, local_host: InetAddress?, local_port: Int): Socket {
val socket = sslSocketFactory.createSocket(host, port, local_host, local_port) as SSLSocket
socket.enabledProtocols = arrayOf("TLSv1.2")
return socket
}
override fun createSocket(host: InetAddress?, port: Int): Socket
{
val socket = sslSocketFactory.createSocket(host, port) as SSLSocket
socket.enabledProtocols = arrayOf("TLSv1.2")
return socket
}
override fun createSocket(address: InetAddress?, port: Int, local_address: InetAddress?, local_port: Int): Socket
{
val socket = sslSocketFactory.createSocket(address, port, local_address, local_port) as SSLSocket
socket.enabledProtocols = arrayOf("TLSv1.2")
return socket
}
override fun getSupportedCipherSuites(): Array<String>
{
return this.sslSocketFactory.getSupportedCipherSuites()
}
}