14

DefaultHttpClient in Android 5.0 Lollipop sembra essere rotto. Non può impostare la connessione ad alcuni siti che sono stati impostati con successo dalle precedenti versioni di Android.HttpClient non riesce con l'handshake non riuscito in Android 5.0 Lollipop

Per esempio ho tenta di connettersi a https://uralsg.megafon.ru

//Create httpclient like in https://stackoverflow.com/questions/18523784/ssl-tls-protocols-and-cipher-suites-with-the-androidhttpclient 
HttpClient client = new DefaultHttpClient(manager, params); 
HttpGet httpGet = new HttpGet("https://uralsg.megafon.ru"); 
HttpResponse client = httpclient.execute(httpGet); 

Questo codice funziona in Android 2,3-4,4, ma non riesce su Android 5.0 (dispositivi e emulatore) con connessione Errore chiusa dal peer. Ovviamente questo è comprensibile perché Android 5.0 tenta di connettere questo vecchio server con TLSv1.2 e codici moderni e non li supporta.

Ok, utilizzando il codice di esempio in SSL/TLS protocols and cipher suites with the AndroidHttpClient limitiamo il protocollo e la cifratura a TLSv1 e SSL_RSA_WITH_RC4_128_MD5. Ora non riesce con un errore diverso:

javax.net.ssl.SSLHandshakeException: Handshake failed 
caused by 
    error:140943FC:SSL routines:SSL3_READ_BYTES:sslv3 alert bad record mac 
    (external/openssl/ssl/s3_pkt.c:1286 0x7f74c1ef16e0:0x00000003) 
    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake 

E naturalmente questo codice viene eseguito senza problemi su Android 2,3-4,4.

ho esaminato il traffico con Wireshark:

302 4002.147873000 192.168.156.30 83.149.32.13 TLSv1 138 Client Hello 
303 4002.185362000 83.149.32.13 192.168.156.30 TLSv1 133 Server Hello 
304 4002.186700000 83.149.32.13 192.168.156.30 TLSv1 1244 Certificate 
305 4002.186701000 83.149.32.13 192.168.156.30 TLSv1 63 Server Hello Done 
307 4002.188117000 192.168.156.30 83.149.32.13 TLSv1 364 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message 
308 4002.240695000 83.149.32.13 192.168.156.30 TLSv1 61 Alert (Level: Fatal, Description: Bad Record MAC) 

Si può vedere che la connessione è stata stabilita, ma del server allertato perché probabilmente non poteva decodificare il messaggio crittografato stretta di mano.

Non sono riuscito a collegarmi a https://uralsg.megafon.ru utilizzando HttpClient su Android 5.0. Il browser di riserva lo connette però. Android 2.3-4.4 collega questo sito in qualsiasi modo senza alcuna difficoltà.

Esiste un modo per consentire a HttpClient di connettere tali siti? Questo è solo un esempio, sono sicuro che ci sono molti server legacy che non possono essere collegati da Android 5.0 e HttpClient.

+0

Ho avuto lo stesso problema con questo. Se conosco la soluzione, aggiungerò commenti. È davvero fastidio – cmcromance

risposta

5

aggiornamento: si è rivelato essere un errore nel back-end, non Android 5, anche se effettivamente con il codice in questione.

Ho avuto lo stesso problema. Per me è risultato essere il codice TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 che è stato scelto dall'insieme di criptaggi predefiniti di Android 5 (aggiornato).

Non appena l'ho rimosso dall'elenco client di cifrari accettabili, le connessioni hanno funzionato di nuovo.

Il android 5 change log cita:

  • AES-GCM (AEAD) cipher suites are now enabled,

Sono abbastanza sicuro che questo è il colpevole. Non appena TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 è preferito (dal server), la connessione avrà esito negativo.

Nota che TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 funziona.

La mia ipotesi è che sia l'implementazione di Android di TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 sia buggata, o quella del server con cui si sta parlando.

Solutions:

  1. Rimuovere TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 dalle cifre disponibili sul server (nessun app ridistribuzione necessario).
  2. Rimuovere TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 dall'elenco di cifre offerte dal client (durante lo CLIENT_HELLO).

Si può fare sul lato client implementando il proprio SSLSocketFactory e chiamando

sslSocket.setEnabledCipherSuites(String[] suites); 

sulla creazione SSLSocket.

modifica: nota che questo non è necessariamente un bug di Android, potrebbe essere che l'implementazione del server sia difettosa. se il tuo problema è effettivamente causato dal cifrario, lascia un commento sul bug tracker di Android] (https://code.google.com/p/android/issues/detail?id=81603). grazie!

+1

Non è così nel mio caso. Nel mio caso il sito supporta solo SSL_RSA_WITH_RC4_128_MD5. E quando lo propongo di usare SSL_RSA_WITH_RC4_128_MD5 fallisce su Lollipop e si connette con successo su Jelly Bean e sotto. –

+0

per quanto ne so, SSL_RSA_WITH_RC4_128_MD5 è stato rimosso dal lollipop per motivi di sicurezza! vedere https://code.google.com/p/android-developer-preview/issues/detail?id=1200#c8 – stefs

+0

Lo so, ma il problema è che l'aggiunta manuale non risolve il caso. –

0

Ho provato a cambiare i cipherSuites in una factory socket personalizzata, ma questo non ha aiutato. Nel mio caso, ho dovuto rimuovere i protocolli TLSv1.1 e TLSv1.2 dai protocolli Enabled del socket. Sembra che alcuni server meno recenti non gestiscano molto bene la negoziazione del protocollo per i nuovi protocolli. Esistono vari esempi per creare un factory socket personalizzato, come ad esempio How to override the cipherlist sent to the server by Android when using HttpsURLConnection? e altri per socket Apache. Fatto questo, ho appena chiamato il seguente metodo AdjustSocket per rimuovere i protocolli.

private void AdjustSocket(Socket socket) 
{ 
    String[] protocols = ((SSLSocket) socket).getSSLParameters().getProtocols(); 
    ArrayList<String> protocolList = new ArrayList<String>(Arrays.asList(protocols)); 

    for (int ii = protocolList.size() - 1; ii >= 0; --ii) 
     { 
     if ((protocolList.get(ii).contains("TLSv1.1")) || (protocolList.get(ii).contains("TLSv1.2"))) 
      protocolList.remove(ii); 
     } 

    protocols = protocolList.toArray(new String[protocolList.size()]); 
    ((SSLSocket)socket).setEnabledProtocols(protocols); 
} 
+0

Ho limitato i protocolli a uno di SSLv3 , TLSv1, TLSv1.1 o superiore manualmente, naturalmente, ma non è stato d'aiuto nel mio caso. –