2012-01-12 19 views
8

Provo a connettermi a un server con un certificato autofirmato. Io uso questo codice per accettare tutti i certificati.Il nome host nel certificato non corrisponde?

public class CertificateAcceptor { 

    public void initializeTrustManager() { 
     try { 
      SSLContext context = SSLContext.getInstance("SSL"); 
      context.init(null, createTrustManager(), new SecureRandom()); 
      HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 

     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (KeyManagementException e) { 
      e.printStackTrace(); 
     } 
    } 

    private TrustManager[] createTrustManager() { 

    TrustManager[] trustAllCerts = new TrustManager[] { 
      new X509TrustManager() { 

       @Override 
       public X509Certificate[] getAcceptedIssuers() { 
        return null; 
       } 

       @Override 
       public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        // leave blank to trust all clients 
       } 

       @Override 
       public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        // leave blank to trust all servers 
        for (X509Certificate c : chain) { 
         System.out.println(c.toString()); 
        } 
       } 

      } 
     }; 
     return trustAllCerts; 
    } 

} 

Ma tuttavia ottengo il seguente errore:

javax.net.ssl.SSLException: hostname in certificate didn't match: <xyz.ch> != <localhost> 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:220) 
    at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:149) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:130) 
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:339) 
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:123) 
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:147) 
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576) 

Sono sicuro che il mio codice certificato viene eseguito, quindi quello che potrebbe essere il problema?

+1

Il problema non è con il gestore di fiducia. La verifica del nome host è una fase di sicurezza separata che controlla il dominio dell'URL che stai richiedendo rispetto a un nome (dovrebbe essere il dominio noto anche come nome host del server) definito nel certificato del server che stai cercando di colpire. Nel tuo caso, il nome nell'URL che stai utilizzando e il nome nel certificato del server non corrispondono. –

risposta

7

È possibile utilizzare SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

SSLSocketFactory sf = new SSLSocketFactory(
    SSLContext.getInstance("TLS"), 
    SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
Scheme sch = new Scheme("https", 443, sf); 
httpclient.getConnectionManager().getSchemeRegistry().register(sch); 

HttpGet httpget = new HttpGet("https://host/"); 
... 
... 
+6

Questa è una risposta errata. Si dovrebbe impostare il certificato con il nome corretto utilizzando keytool con il 'estensione ext': ' '' keytool -genkeypair \ -keystore keystore.jks \ -dname "CN = OLEKSIYS-W3T, OU = Sun Java System Application Server, O = Sun Microsystems, L = Santa Clara, California ST =, C = US" \ -keypass changeit \ -storepass changeit \ -keyalg RSA \ -keysize 2048 \ -alias s1as \ -ext SAN = DNS: localhost, IP: 127.0.0.1 \ -validity 9999 '' ' e vedere http://tersesystems.com/2014/03/23/fixing-hostname-verification/ –

+1

Questo sicuramente funziona, ma @WillSarge ha ragione. Se utilizzi un approccio "consenti tutti", la tua app diventa vulnerabile. Probabilmente starai bene con un'app che non è eccessivamente popolare ma fai attenzione quando si tratta di progetti di lavoro/freelance. – Jacksonkr

+2

@Jackson è peggio di così. L'FTC ha citato in giudizio le persone per aver disabilitato la sicurezza in questo modo. http://www.ftc.gov/news-events/press-releases/2014/03/fandango-credit-karma-settle-ftc-charges-the-deceived-consumers –

1

La risposta da Prashant potrebbe non funzionare, come è necessario inizializzare il SSLContext pure.

lo farei qualcosa di simile,

SSLSocketFactory sf=null ; 
     SSLContext sslContext = null; 
     StringWriter writer; 
     try { 
      sslContext = SSLContext.getInstance("TLS") ; 
      sslContext.init(null,null,null); 
     } catch (NoSuchAlgorithmException e) { 
      //<YourErrorHandling> 
     } catch (KeyManagementException e){ 
      //<YourErrorHandling> 
     } 

     try{ 
      sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

     } catch(Exception e) { 
      //<YourErrorHandling> 

    } 
     Scheme scheme = new Scheme("https",443,sf); 
     httpClient.getConnectionManager().getSchemeRegistry().register(scheme); 
15

ALLOW_ALL non è la risposta corretta. Si dovrebbe impostare il certificato con il nome corretto utilizzando keytool con l'estensione ext:

keytool -genkeypair \ 
    -keystore keystore.jks \ 
    -dname "CN=OLEKSIYS-W3T, OU=Sun Java System Application Server, O=Sun Microsystems, L=Santa Clara, ST=California, C=US" \ 
    -keypass changeit \ 
    -storepass changeit \ 
    -keyalg RSA \ 
    -keysize 2048 \ 
    -alias default \ 
    -ext SAN=DNS:localhost,IP:127.0.0.1 \ 
    -validity 9999 

Vedere http://tersesystems.com/2014/03/23/fixing-hostname-verification/ per maggiori dettagli.

+0

Dopo aver generato il keystore, lo si inizializza separatamente o come parte di un 'SSLContext'? Se hai tempo per guardare la mia [domanda completa] (http://stackoverflow.com/questions/30105561/find-or-intialize-the-keystore-needed-to-solve-hostname-in-certificate-didnt-m) Lo apprezzerei. –

+0

È necessario aggiungere il certificato al proprio archivio di fiducia. Il solito modo per farlo è aggiungerlo ai cacerts usando keytool, o per impostare la proprietà di sistema javax.net.ssl.trustStore in modo che punti ad un altro negozio di fiducia. –

0

Il mio problema era che Java SE 6 o inferiore non supporta SNI. Ciò significa che un solo IP può avere solo un certificato SSL. Ma sul mio server c'erano 3 diversi apis con diversi certificati SSL. Java SE 7 o maggiore supporto SNI e tutto ha funzionato bene. (o solo eseguendo una API sul server)

Problemi correlati