2012-01-12 37 views
8

intento conectar a un servidor con un certificado autofirmado. Yo uso este código para aceptar todos los certificados.¿El nombre de host en el certificado no coincide?

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

} 

Pero sin embargo me sale el siguiente error:

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) 

Estoy seguro de que se ejecuta el código de certificado, así que lo que podría ser el problema?

+1

El problema no es con el TrustManager. verificación de nombre de host es un paso de seguridad independiente que comprueba el dominio de la URL que está solicitando en contra de un nombre (debe ser el dominio alias nombre de host del servidor) se define en el certificado del servidor al que está intentando golpear. En su caso, el nombre en la URL que está usando y el nombre en el certificado del servidor no coinciden. –

Respuesta

7

Es posible utilizar 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

Esta es una respuesta incorrecta. Es necesario configurar su certificado con el nombre correcto mediante el uso de herramienta de claves con la extensión 'ext': ' '' herramienta de claves -genkeypair \ -keystore keystore.jks \ -dNOMBRE "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 \ -validez 9999 '' ' y ver http://tersesystems.com/2014/03/23/fixing-hostname-verification/ –

+1

Esto definitivamente workse, pero @WillSarge nt es correcto. Si usa un enfoque de "permitir todo", su aplicación se vuelve vulnerable. Probablemente estarás bien con una aplicación que no sea demasiado popular, pero ten cuidado cuando se trata de proyectos de trabajo/freelance. – Jacksonkr

+2

@Jackson es mucho peor que eso. La FTC ha demandado a personas por deshabilitar la seguridad de esta manera. http://www.ftc.gov/news-events/press-releases/2014/03/fandango-credit-karma-settle-ftc-charges-they-deceived-consumers –

1

La respuesta por Prashant puede no funcionar, como sea necesario para inicializar el SSLContext también.

lo haría algo así,

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 no es la respuesta correcta. Es necesario configurar su certificado con el nombre correcto mediante el uso de herramienta de claves con la extensión 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 

Ver http://tersesystems.com/2014/03/23/fixing-hostname-verification/ para más detalles.

+0

Después de generar el almacén de claves, ¿lo inicializa por separado o como parte de un 'SSLContext'? Si tiene tiempo para ver mi [pregunta completa] (http://stackoverflow.com/questions/30105561/find-or-intialize-the-keystore-needed-to-solve-hostname-in-certificate-didnt-m) Lo apreciaría. –

+0

Necesita agregar el certificado a su tienda de confianza. La forma habitual de hacerlo es agregarlo a cacerts utilizando keytool o establecer la propiedad del sistema javax.net.ssl.trustStore para que apunte a otro almacén de confianza. –

0

Mi problema era, que Java SE 6 o más pequeño no es compatible con SNI. Eso significa que ese IP solo puede tener un certificado SSL. Pero en mi servidor, había 3 apis diferentes con diferentes certs ssl. Java SE 7 o superior soporta SNI y todo funcionó bien. (O sólo ejecutar una API en el servidor)

Cuestiones relacionadas