我正在構建一個應用程序,該應用程序通過HTTPS
獲取一些JSON
數據,使用自定義OkHttp
客戶端進行改裝。它在KitKat上正常工作。一旦我轉移到Android 5,6或7,SSL
握手失敗。改裝:在API21 +設備上啓動時,Android應用程序失敗SSL握手
服務器支持TLSv1
,沒有別的。它還使用了一個古老的,過期的自簽名證書。測試它與Qualys的SSL工具,它告訴我所有版本的Android應該能夠連接。下面是我得到了什麼:
OkHttp客戶端:
public class HTTPClient {
public static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create a ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//URL url = new URL(ApiIntentService.getHostAddress());
//final SSLSocketFactory sslSocketFactory = new NoSSLv3SocketFactory(url);
// ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
// .tlsVersions(TlsVersion.TLS_1_0)
// .cipherSuites(
// CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
// CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
// CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
// CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
// CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
// CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
// CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
// CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
// CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
// CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
// .build();
// String hostname = "api.server.domain";
// CertificatePinner certificatePinner = new CertificatePinner.Builder()
// .add(hostname, "sha256/3Iiwgs3a0qjPCnBQzW/GeHhPbZvhaJtxKvMJJVO5KdU=")
// .build();
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
// builder.connectionSpecs(Collections.singletonList(spec));
// builder.certificatePinner(certificatePinner);
builder.sslSocketFactory(sslSocketFactory);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
builder.authenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("user", "pass");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
我知道如何可怕在安全性方面這個代碼是屠殺。我的主管要求這樣做,我告訴他這有多糟糕。
我已經嘗試了兩件事情來解決我的問題,他們在那段代碼 - 證書固定和請求TLSv1
註釋掉了一部分密碼。在其他問題中找到這兩個問題,但他們沒有任何改變(堆棧跟蹤完全相同)。
堆棧跟蹤
這裏是堆棧跟蹤的有趣的位:
I/RETROFIT: Data retrieval failed! javax.net.ssl.SSLHandshakeException: Handshake failed
*snip*
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb43eb200: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:770 0xac6fedd4:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
看起來好像Android的嘗試使用SSLv3
突然,但Wireshark的顯示通過TLSv1
通信。它應該從Client Hello
開始,但服務器立即以Handshake Failure (40)
回答。
所有的幫助都非常容易理解,因爲我全都沒有想法。如果需要,請要求澄清。
謝謝。
您是否嘗試過註釋掉'ConnectionSpec'件與'ConnectionSpec.MODERN_TLS'取代'ConnectionSpec.COMPATIBLE_TLS' –
是的,我有。它最初是在那裏,我在閱讀文檔後改變了它。雖然沒有效果。 –