2012-01-12 14 views
8

Próbuję połączyć się z serwerem za pomocą certyfikatu z podpisem własnym. Używam tego kodu do akceptowania wszystkich certyfikatów.Nazwa hosta w certyfikacie nie jest zgodna?

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; 
    } 

} 

Niemniej jednak pojawia się następujący błąd:

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) 

Jestem pewien, że mój kod certyfikatu jest wykonywana, więc co może być problemem?

+1

Problem nie dotyczy menedżera zaufania. Weryfikacja nazwy hosta jest oddzielnym krokiem zabezpieczającym, który sprawdza domenę żądanego adresu URL pod nazwą (powinna to być nazwa domeny nazwa hosta serwera) zdefiniowana w certyfikacie serwera, który próbujesz trafić. W twoim przypadku nazwa w adresie URL, którego używasz, i nazwa w certyfikacie serwera nie są zgodne. –

Odpowiedz

7

Można użyć 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

To jest niepoprawna odpowiedź. należy skonfigurować swój certyfikat z poprawną nazwą używając keytool z 'ext' rozszerzenia: ' '' keytool -genkeypair \ -keystore keystore.jks \ -dnazwa „CN = OLEKSIYS-W3T, OU = Słońca Java Application system 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 '' ' i zobacz http://tersesystems.com/2014/03/23/fixing-hostname-verification/ –

+1

To zdecydowanie działa, ale @WillSarge Nt ma rację. Jeśli zastosujesz podejście "zezwól na wszystko", Twoja aplikacja stanie się zagrożona. Prawdopodobnie będzie dobrze z aplikacją, która nie jest zbyt popularna, ale zachowaj ostrożność, jeśli chodzi o projekty związane z pracą/wolnym. – Jacksonkr

+2

@ Jackson jest o wiele gorszy. FTC oskarżyło ludzi o wyłączenie bezpieczeństwa w ten sposób. http://www.ftc.gov/news-events/press-releases/2014/03/fandango-credit-karma-settle-ftc-charges-they-deceived-consumers –

1

Odpowiedź przez Prashant może nie działać, jak trzeba zainicjować SSLContext również.

zrobiłbym to coś,

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 nie jest prawidłowa odpowiedź. należy skonfigurować swój certyfikat z poprawną nazwą używając keytool z rozszerzeniem 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 

Zobacz http://tersesystems.com/2014/03/23/fixing-hostname-verification/ więcej szczegółów.

+0

Po wygenerowaniu magazynu kluczy, zainicjujesz go osobno lub jako część 'SSLContext'? Jeśli masz czas spojrzeć na moje [pełne pytanie] (http://stackoverflow.com/questions/30105561/find-or-intialize-the-keystore-eded-to-solve-hostname-in-certyfikat-didnt-m) Doceniłbym to. –

+0

Musisz dodać certyfikat do swojego magazynu zaufanych certyfikatów. Najczęstszym sposobem na to jest dodanie go do cacerts za pomocą keytool lub ustawienie właściwości systemowej javax.net.ssl.trustStore w celu wskazania innego magazynu zaufanych certyfikatów. –

0

Mój problem polegał na tym, że Java SE 6 lub mniejsza nie obsługuje SNI. Oznacza to, że jeden adres IP może mieć tylko jeden certyfikat ssl. Ale na moim serwerze były 3 różne apisy z różnymi certyfikatami ssl. Java SE 7 lub nowsza obsługa SNI i wszystko działało dobrze. (lub tylko uruchamianie jednego api na serwerze)

Powiązane problemy