Я создаю приложение, которое извлекает данные JSON
через HTTPS
, используя Модернизацию с заказчиком OkHttp
. Он отлично работает на KitKat. Как только я перейду на Android 5, 6 или 7, SSL
рукопожатия терпят неудачу.Модификация: Android-приложение не работает SSL-рукопожатия при запуске на устройствах API21 +
Сервер поддерживает TLSv1
и ничего больше. Он также использует древний, истекший, самозаверяющий сертификат. Протестировал его с помощью инструмента SSL Qualys, который сказал мне, что все версии 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);
}
}
Я знаю, как страшно разделывали с точки зрения безопасности этот код является. Мой руководитель потребовал, чтобы это было так, и я сообщил ему, насколько это плохо.
Я пробовал 2 вещи, чтобы решить мою проблему, они закомментированы в этом фрагменте кода - сертификате и запросе 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' –
Да, у меня есть. Первоначально он был там, я изменил его, прочитав документацию. Однако никакого эффекта. –