2010-06-22 18 views
27

Estoy intentando conectarme a uno de mis servidores a través de ssl, con Java. He intentado un montón de opciones aquí es mi mejor intento:CertificateException: No se ha encontrado ningún nombre que coincida con ssl.someUrl.de

genero un jssecacerts con el guión recommendet: http://blogs.oracle.com/andreas/resource/InstallCert.java con el comando: java InstallCert ssl.someUrl.de changeit

después de esto hice el comando de una segunda vez:

Loading KeyStore jssecacerts... 
Opening connection to ssl.someUrl.de:443... 
Starting SSL handshake... 

No errors, certificate is already trusted 

Server sent 1 certificate(s): 

1 Subject [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd 
on, ST=Virginia, C=US 
    Issuer [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd 
on, ST=Virginia, C=US 
    sha1 f1 0d 2c 54 05 e1 32 19 a0 52 5e e1 81 6c a3 a5 83 0d dd 67 
    md5  f0 b3 be 5e 5f 6e 90 d1 bc 57 7a b2 81 ce 7d 3d 

Enter certificate to add to trusted keystore or 'q' to quit: [1] 

que copiar el archivo en el directorio predeterminado y me carga el certificado en Java trustStore

System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files (x86)\\Java\\jre6\\lib\\security\\jssecacerts"); 
System.setProperty("javax.net.ssl.trustStorePassword","changeit"); 

Entonces intento conectar

URL url = new URL("https://ssl.someUrl.de/"); 
URLConnection conn = url.openConnection(); 
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); 

y me sale un error en la 3ª línea: (Sin nombre coincide con ssl.someUrl.de encontró)

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching ssl.someUrl.de found 

¿Es esta la causa del certificado plesk o por defecto es algo más está mal?

Configuración: JRE 6.20, Netbeans 6.8, Windows 7 de 64 bits

Respuesta

39

Parece que el certificado del servidor al que está intentando conectarse a no coincide con su nombre de host.

Cuando un cliente HTTPS se conecta a un servidor, verifica que el nombre de host en el certificado coincida con el nombre de host del servidor. No es suficiente que un certificado sea confiable, también tiene que coincidir con el servidor con el que desea hablar. (A modo de analogía, incluso si confía en que un pasaporte sea legítimo, igual debe verificar que sea el de la persona con la que desea hablar, no solo el pasaporte en el que confíe que es legítimo)

In HTTP, esto se hace mediante la comprobación de que:

  • el certificado contiene un nombre alternativo del sujeto DNS (esto es una extensión estándar) entrada que coincida con el nombre de host;

  • En su defecto, el último CN de su nombre distinguido (este es el nombre principal si lo desea) coincide con el nombre de host. (Véase el RFC 2818.)

Es difícil decir cuál es el nombre alternativo del sujeto es sin tener el certificado (aunque, si se conecta con su navegador y comprobar su contenido en más detalles, debe ser capaz de ver . es) El nombre completo sujeto parece ser:

[email protected], CN=plesk, OU=Plesk, O=Parallels, L=Herndon, ST=Virginia, C=US 

(por lo que tendría que ser CN = ssl.someUrl.de en lugar de CN = Plesk, si usted no tiene un nombre alternativo del sujeto con DNS: ssl.someUrl.de ya; supongo que no es así).

Puede omitir la verificación de nombre de host usando HttpsURLConnection.setHostnameVerifier(..). No debería ser demasiado difícil escribir un HostnameVerifier personalizado que invalide la verificación, aunque sugeriría que lo haga solo cuando el certificado sea el relacionado aquí específicamente. Debería poder obtenerlo utilizando el argumento SSLSession y su método getPeerCertificates().

(Además, no es necesario para establecer el javax.net.ssl. * Propiedades de la manera que lo ha hecho, ya que usted está usando los valores por defecto de todos modos.)

Alternativamente, si usted tiene control sobre el servidor al que se está conectando y su certificado, puede crear un certificado que coincida con las reglas de denominación anteriores (CN debería ser suficiente, aunque el nombre alternativo del sujeto sea una mejora). Si un certificado autofirmado es lo suficientemente bueno para lo que usted nombra, asegúrese de que su nombre común (CN) sea el nombre de host con el que está tratando de hablar (no la URL completa, solo el nombre de host).

+0

thx Lo hice con el HostnameVerifier. Solo necesito una conexión encriptada. Solo hay un cliente y un servidor, con un htts: // dirección fijo. – fehrlich

+1

Recuerde que * necesita * algún tipo de verificación de identidad de cifrado para proporcionar seguridad. De lo contrario, es como intercambiar secretos con alguien que no conoces: por muy bueno que sea el método secreto, eso realmente no te protege. – Bruno

+0

pero conozco el servidor y el único cliente (que está en mi computadora) y nadie puede leer la secuencia de datos. Y la página https también está protegida con un simple acceso htaccess. ¿O estoy equivocándome? – fehrlich

3

he encontrado una buena resolución aquí: http://www.mkyong.com/webservices/jax-ws/java-security-cert-certificateexception-no-name-matching-localhost-found/

Pero mi problema era un poco diferente y lo resolvió de manera diferente.

El servicio web estaba en el host remoto. Por ejemplo: https://some.remote.host/MyWebService?wsdl

Pero estaba disponible solo por IP para los clientes, pero se creó un certificado para el dominio: some.remote.host (CN = some.remote.host). Y este dominio no se puede resolver por IP porque no se presenta en DNS).

Así que apareció el mismo problema: si utilizo IP para conectarme al servicio web por ssl, no puede ser alcanzado porque el certificado CN = some.remote.host y no es igual al nombre de host que he especificado (es decir, IP de host).

Lo he resuelto haciendo coincidir este nombre de host con IP en el archivo/etc/hosts. El problema se solucionó.

Pero en caso de que el servicio web esté alojado en el servidor de la aplicación localhost, piense que debería resolverse como se describe en su artículo.

1

El nombre de servidor debe ser el mismo que el primer nombre/última que le dan mientras que crear un certificado

15

En Java 8 puede omitir el nombre del servidor de comprobar con el siguiente código:

HttpsURLConnection.setDefaultHostnameVerifier ((hostname, session) -> true); 

Sin embargo, esta ¡debe usarse solo en desarrollo!

+0

genial, gracias. más ayuda aquí: http://www.mkyong.com/webservices/jax-ws/java-security-cert-certificateexception-no-name-matching-localhost-found/ – OhadR

7

Creé un método fixUntrustCertificate(), así que cuando estoy tratando con un dominio que no está en CA de confianza, puede invocar el método antes de la solicitud. Este código funcionará después de java1.4. Este método se aplica a todos los hosts:

public void fixUntrustCertificate() throws KeyManagementException, NoSuchAlgorithmException{ 


     TrustManager[] trustAllCerts = new TrustManager[]{ 
      new X509TrustManager() { 
       public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
        return null; 
       } 

       public void checkClientTrusted(X509Certificate[] certs, String authType) { 
       } 

       public void checkServerTrusted(X509Certificate[] certs, String authType) { 
       } 

      } 
     }; 

     SSLContext sc = SSLContext.getInstance("SSL"); 
     sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

     HostnameVerifier allHostsValid = new HostnameVerifier() { 
      public boolean verify(String hostname, SSLSession session) { 
       return true; 
      } 
     }; 

     // set the allTrusting verifier 
     HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); 
} 
Cuestiones relacionadas