2017-02-03 23 views
3

Я создаю приложение, которое извлекает данные 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).

Вся помощь очень проницательна, так как у меня все идеи. Пожалуйста, уточните, если это необходимо.

спасибо.

+0

Вы пробовали закомментирована 'ConnectionSpec' часть с' ConnectionSpec.MODERN_TLS' вместо 'ConnectionSpec.COMPATIBLE_TLS' –

+0

Да, у меня есть. Первоначально он был там, я изменил его, прочитав документацию. Однако никакого эффекта. –

ответ

2

Сообщите своему супервизору, что ваши HTTP-клиенты не могут подключиться к смертельно опасным серверам HTTPS. Вы можете сказать, что это ограничение компьютеров, и единственным вариантом является обновление сервера.

Как только вы это сделаете, вы можете добавить режим отладки только для разработки. Чтобы сделать это, включите набор шифров, который поддерживает ваш сервер. Вы можете получить список из инструмента Qualys.

+0

Получил работу на тестовом сервере RPi (с использованием TLSv1.2), протестированном на нескольких устройствах с различными версиями Android. Это, очевидно, не проблема с приложением. Благодарю за ваш ответ. –

1

Решение для меня добавляло больше шифров в качестве приемлемого для OkHttpClient. Начиная с API 21, некоторые TLS-сертификаты устарели для Android. Это может помочь:

ConnectionSpec spec = new 
ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 
      .tlsVersions(TlsVersion.TLS_1_2) 
      .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) 
      .build(); 

OkHttpClient client = new OkHttpClient.Builder() 
     .connectionSpecs(Collections.singletonList(spec)) 
     .build(); 

Для получения дополнительной информации, пожалуйста, посетите: https://github.com/square/okhttp/wiki/HTTPS

+0

Не работал для меня. –

+0

Насколько я помню, я попытался добавить много разных шифров, и это просто не сработало. Обновление программного обеспечения сервера было способом. –

 Смежные вопросы

  • Нет связанных вопросов^_^