2010-06-28 17 views
17

Sto utilizzando HttpClient su Android per connettersi a https://someUrl.com/somePath. Il problema è che il certificato del sito è per * .someUrl.com, non someUrl.com, quindi ricevo una SSLException. Zoppo sulla parte del sito, sì, ma a meno che non riesca a farlo riparare, sono bloccato. C'è un modo per far sì che HttpClient si rilassi e accetti il ​​certificato?HttpClient Android: il nome host nel certificato non corrisponde a <example.com>! = <*. Esempio.com>

risposta

33

Questo è il mio (a cura) Soluzione:

class MyVerifier extends AbstractVerifier { 

    private final X509HostnameVerifier delegate; 

    public MyVerifier(final X509HostnameVerifier delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public void verify(String host, String[] cns, String[] subjectAlts) 
       throws SSLException { 
     boolean ok = false; 
     try { 
      delegate.verify(host, cns, subjectAlts); 
     } catch (SSLException e) { 
      for (String cn : cns) { 
       if (cn.startsWith("*.")) { 
        try { 
          delegate.verify(host, new String[] { 
           cn.substring(2) }, subjectAlts); 
          ok = true; 
        } catch (Exception e1) { } 
       } 
      } 
      if(!ok) throw e; 
     } 
    } 
} 


public DefaultHttpClient getTolerantClient() { 
    DefaultHttpClient client = new DefaultHttpClient(); 
    SSLSocketFactory sslSocketFactory = (SSLSocketFactory) client 
      .getConnectionManager().getSchemeRegistry().getScheme("https") 
      .getSocketFactory(); 
    final X509HostnameVerifier delegate = sslSocketFactory.getHostnameVerifier(); 
    if(!(delegate instanceof MyVerifier)) { 
     sslSocketFactory.setHostnameVerifier(new MyVerifier(delegate)); 
    } 
    return client; 
} 

Ha il vantaggio di non cambiare il comportamento di default a meno che non ci sia un dominio jolly, e in tal caso riconvalida come se il dominio a 2 parti (ad esempio, someUrl.com) fosse parte del certificato, altrimenti l'eccezione originale viene riconsegnata. Ciò significa che i certificati non validi continueranno a fallire.

+0

Ho provato a utilizzare il precedente, ma a volte ottengo eccezioni di overflow dello stack: il metodo verify() non si arresta mai. Su poche centinaia di migliaia di installazioni, accade circa 80 volte a settimana. Hai riscontrato problemi con questo? – user291701

+0

@ user291701 Ho modificato il codice per provare a risolvere il problema. Direi che il problema è che si finisce per impostare nuovamente il verificatore sulla stessa fabbrica, quindi finisce per delegare a se stesso in qualche modo ... Sentiti libero di modificare la mia risposta se trovi un modo migliore. – noah

+0

In ogni caso, sto affrontando "il server non può servire la richiesta perché il tipo di supporto non è supportato". Non ho idea di quale sia la ragione di ciò. –

1

Se si desidera *.someUrl.com, sembra che si potrebbe semplicemente dargli www.someUrl.com/somePath anziché someUrl.com/somePath.

+1

Nope. www.someUrl.com reindirizza a somerl.com – noah

+0

Suppongo che sia inutile, quindi. Hai davvero bisogno di https? Direi di sì, ma questo renderebbe la vita molto più facile. –

+0

Questa è una grande soluzione temporanea quando il sito NON esegue un reindirizzamento! –

3

Il BouncyCastle su Android è troppo vecchio e non riconosce il certificato con caratteri jolly.

È possibile scrivere il proprio X509TrustManager per verificare la presenza di caratteri jolly.

oppure è possibile disabilitare del tutto il controllo del certificato se è possibile accettare il rischio. Vedere questa domanda,

Self-signed SSL acceptance on Android

+0

In realtà ZZ, se l'OP è corretto sul nome del sito e sulla struttura del certificato, il messaggio di errore è corretto: **. SomeUrl.com * deve corrispondere a www.someUrl.com e any.someUrl. com, ma * not * someUrl.com o this.that.someUrl.com. –

1

se si utilizza un WebView basta chiamare

webview.clearSslPreferences(); 

di ignorare errori SSL