鉴于使用httpclient连接到第三方网站的Android应用,如何从较旧的Android设备获得成功的SSL连接?
此前,当前和较旧的Android版本均有效,但第三方网站更改了其SSL配置。这引发了一个错误,但仅限于较旧的Android平台:
System.err: javax.net.ssl.SSLException: Connection closed by peer
System.err: at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:406)
在做了一些研究(google issue tracker)之后,我想我可能会尝试从可用协议列表中删除SSLv3
。我已经能够做到这一点,并且还缩小了密码套件的数量,但仍然存在SSLException
问题。
使用httpclient-4.4.1.2
的代码会修补以允许SNI,并且适用于较新的Android(API 22),但不适用于较旧的Android(API 15):
nHttpclient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).setDefaultCookieStore(nCookieStore).build();
以下是我一直在尝试的一些代码。虽然我能够删除SSLv3,但我仍然无法建立安全连接:
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
SSLContextBuilder contextBuilder = SSLContextBuilder.create();
contextBuilder.useProtocol("TLSv1");
SSLContext sslContext = contextBuilder.build();
clientBuilder.setSslcontext(sslContext);
nHttpclient = clientBuilder.setRedirectStrategy(new LaxRedirectStrategy()).setDefaultCookieStore(nCookieStore).build();
上述代码限制协议包含TLSv1
(不再包含SSLv3
。此外,我暂时更改了SSLConnectionSocketFactory.createLayeredSocket()
,以便套接字仅包含新密码和新密码套件中包含的密码套件旧的Android平台。换句话说,我删除了一堆未在新Android平台上报告的套件。
因此,限制为TLSv1
并限制为较新的密码套件,我仍然收到错误,但无法建立安全连接。
登录较旧的Android:
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: Enabled protocols: [TLSv1]
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: !!Enabled cipher suites:[TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: Starting handshake
cz.msebera.android.httpclient.impl.conn.DefaultManagedHttpClientConnection: http-outgoing-1: Shutdown connection
cz.msebera.android.httpclient.impl.execchain.MainClientExec: Connection discarded
cz.msebera.android.httpclient.impl.conn.DefaultManagedHttpClientConnection: http-outgoing-1: Close connection
在较新的Android上运行相同的代码:
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: Enabled protocols: [TLSv1, TLSv1.1, TLSv1.2]
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: Enabled cipher suites:[TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: Starting handshake
cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory: Secure session established
当访问的网站已更新为较新的SSL / TLS标准时,使旧的Android平台能够使用httpclient-4.4.1.2
(或类似),这一定是一个常见问题。
我使用API 15
进行的实验表明,拥有管理SNI的httpclient代码,删除了SSLv3
,以及删除了较旧的密码套件仍然不允许安全连接,而是在SSLException
中抛出SSL_do_handshake()
。
如果我试图强迫旧的Android使用TLSv1.1,我会得到:
java.security.NoSuchAlgorithmException: SSLContext TLSv1.1 implementation not found
API 15
或更低TLSv1.1
research indicates永远不会与API 16
及更高版本一起使用,但API 19
到API 20
可能会有效,但是默认情况下不启用较新的协议。 API 16
及更高版本,默认情况下启用较新的协议 。
在xx <- array(rnorm(120), dim = c(2, 3, 4, 5))
ii <- array(sample(1:5, replace = T, size = 24), dim = c(2,3,4))
范围的Android操作系统上允许从httpclient进行安全连接需要做些什么?
答案 0 :(得分:0)
问题是httpclient-android
代码使用getEnabledProtocols()
代替getSupportedProtocols()
。
我使用的 work around 是获取source code for smarek httpclient-android,将其拉入我项目的模块中,删除对{{预构建版本}的引用1}},然后更改httpclient-android
中的一行:
SSLConnectionSocketFactory.java
这具有允许连接到我试图在API 16,17,18和19上访问的第三方网站的效果。
我认为从API 15或更低版本访问TLSv1.1或TLSV1.2是“不可能的”,除非您愿意在Android操作系统级别进行一些重大更改。
但是,这个简单的更改允许在较旧的Android版本上运行的应用访问不再支持旧版SSL和TLSv1的网站。