2012-04-10 10 views
6

Recibí el nombre de host excepción incorrecta. He usado this code (lo obtuve de algún enlace) en mi programa.Mi programa está funcionando bien.Mi pregunta es lo suficientemente seguro? (Ya que no está validando cadenas de certificados)nombre de host excepción incorrecta

public class Host { 

    public String subscribe() throws Exception { 
     String resp = ""; 
     String urlString="https://xxx.xxx.xx.xx:8443/WebApplication3/NewServlet"; 
     URL url; 
     URLConnection urlConn; 
     DataOutputStream printout; 
     DataInputStream input; 
     String str = ""; 
     int flag=1; 

     try { 
      HostnameVerifier hv = new HostnameVerifier() { 
       public boolean verify(String urlHostName, SSLSession session) { 
        System.out.println("Warning: URL Host: " + urlHostName + " vs. " 
         + session.getPeerHost()); 
        return true; 
       } 
      }; 

      trustAllHttpsCertificates(); 
      HttpsURLConnection.setDefaultHostnameVerifier(hv); 

      url = new URL(urlString); 
      urlConn = url.openConnection(); 
      urlConn.setDoInput(true); 
      Object object; 
      urlConn.setUseCaches(false); 

      urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
      input = new DataInputStream(urlConn.getInputStream()); 

      while (null != ((str = input.readLine()))) { 
       if (str.length() >0) { 
        str = str.trim(); 
        if(!str.equals("")) { 
         //System.out.println(str); 
         resp += str; 
        } 
       } 
      } 
      input.close(); 
     } catch (MalformedURLException mue) { 
      mue.printStackTrace(); 
     } catch(IOException ioe) { 
      ioe.printStackTrace(); 
     } 
     return resp; 
    } 

    public static class miTM implements javax.net.ssl.TrustManager, 
     javax.net.ssl.X509TrustManager { 

     public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 

     public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) { 
      return true; 
     } 

     public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) { 
      return true; 
     } 

     public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { 
      return; 
     } 

     public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { 
      return; 
     } 
    } 

    private static void trustAllHttpsCertificates() throws Exception { 

     // Create a trust manager that does not validate certificate chains: 
     javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; 

     javax.net.ssl.TrustManager tm = new miTM(); 

     trustAllCerts[0] = tm; 

     javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL"); 

     sc.init(null, trustAllCerts, null); 

     javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

    } 

} 
+2

Por favor, publique su código (sin líneas comentadas) como parte de su pregunta. – MByD

+0

@Binyamin Sharet: Código publicado como parte de mi pregunta. – user10101

+0

> Mi pregunta es ¿es lo suficientemente segura?

Respuesta

4

El código en miTM realidad desactiva los controles de seguridad SSL, por lo que el nivel de seguridad es bastante bajo (sólo obtendrá errores si el certificado SSL está roto, pero usted don' t recibe errores cuando el certificado no coincide con el dominio).

Básicamente, intenta hacer una conexión sin ningún tipo de seguridad. Si eso es lo que desea, la solución podría ser "lo suficientemente segura", pero lo más probable es que la respuesta sea "no".

La solución correcta para este tipo de problema es crear un certificado coincidente para este dominio.

Desafortunadamente, esto no es posible cuando su servidor HTTP está utilizando "alojamiento virtual" (= muchos nombres de dominio se asignan a la misma dirección IP). La solución correcta para este problema es obtener su propia dirección IP.

Si todavía quiere probar una solución de Java-solamente, echar un vistazo a esta respuesta: https://stackoverflow.com/a/3293720/34088

+0

: He visto este enlace también ... En realidad, mi código pertenece al del enlace (que termina con -> tutorialid = 211) dado en ese enlace. ¿Cuál es la solución? – user10101

+0

Deshágase de 'trustAllHttpsCertificates()'. Establecer el 'HostnameVerifier' debería ser suficiente. –

+0

Acabo de comentar la línea trustAllHttpsCertificates(); en el método de servicio ... solo deshabilitado la llamada de la función ¿es suficiente? – user10101

1

Aquí es una manera de limpiar su código y permanecer seguro. Supongo que el código se conecta a un servicio conocido (de confianza). Para hacer que la pila SSL de Java acepte la conexión incluso con la discrepancia del nombre de host, la mejor manera es agregar el certificado del servidor al almacén de confianza de JVM.

Primero puede exportar el certificado del servidor desde su navegador y guardarlo en el disco. Desde Linux, puede usar openssl s_client -connect xxx.xxx.xx.xx:8443 y copiar/pegar el certificado del servidor en formato ascii-blindado en un archivo de texto.

luego importar el certificado de servidor en jre/lib/security/cacerts archivo JKS con herramienta de claves

keytool -import -alias myservice -file servercertificate.cer 

Otra opción prefiero, para evitar la regresión cuando Java se actualiza, es copiar cacerts en su propio lugar y declara que gracias a la javax.net.ssl.trustStore propiedad del sistema.

Como el certificado del servidor está en el almacén de confianza ... es de confianza, hasta que caduque. Esto se usa a menudo para certificados de servidor autofirmados.

1

muchas veces en Java utilizado para obtener este tipo de excepciones

problema podría ser ipconflict/ip-dominio desajuste/desactivar prueba

lo he resuelto mediante su dirección IP apropiada y la instalación de certificados.

1

Para hacer la conexión que asegure MUST (al menos):

  • verificar que confía en el certificado,
  • verificar el nombre de host (a menos que sepa con certeza que este es el único y solo certificado en el que usted confíe tal vez).

Su código falla en esos dos puntos:

  • El TrustManager que está utilizando no comprueba el certificado en absoluto (que nunca se produce una excepción, mientras que la API de espera que se lance una forma de CertificateException cuando el certificado no es de confianza).
  • Su verificador de nombre de host siempre devuelve true.

para fijar su código:

  • Mantener los administradores de confianza predeterminado, o inicializar ellas con su propio almacén de confianza y el valor predeterminado TrustManagerFactory.
  • Conservar el verificador de nombre de host predeterminado.

El título de tu pregunta ("nombre de host excepción equivocada") y su URL de ejemplo https://xxx.xxx.xx.xx:8443 parece sugerir que se está conectando a una dirección IP.

A diferencia de otros navegadores, Java sigue la especificación (RFC 2818) muy estrictamente en esto:

Si una extensión subjectAltName de tipo dNSName está presente, que debe ser utilizado como la identidad. De lo contrario, DEBE utilizarse el campo Nombre (más específico) Común en el campo Asunto del certificado. Aunque el uso del Nombre común es una práctica existente, es obsoleto y se recomienda a las Autoridades de certificación que usen el dNSName.

[...]

En algunos casos, el URI se especifica como una dirección IP en lugar de un nombre de host. En este caso, el asunto iPAddressAltName debe estar presente en el certificado y debe coincidir exactamente con la dirección IP en el URI.

Esto significa que no puede salirse con la suya simplemente colocando la dirección IP en el Nombre común (CN) de su DN de asunto en su certificado de servidor. Si está usando una dirección IP, DEBE estar en una entrada de Nombre alternativo del sujeto. (A partir de Java 7, keytool tiene opciones para generar dichos certificados.)

Encontrará más detalles sobre qué comandos usar en this answer.

Dicho esto, el uso de direcciones IP solo puede funcionar a lo sumo en un entorno de prueba. No creo que ninguna CA comercial le otorgue un certificado basado en la dirección IP. Sugiero configurar entradas de DNS (incluso si está solo en los archivos hosts en un entorno de prueba).

Incluso si no está utilizando la dirección IP, debe asegurarse de que ese certificado sea válido para el nombre de host con el que intenta contactar con el servidor: si tiene entradas de nombre alternativo del sujeto, una de ellas debe coincide con el nombre de host; de lo contrario, el nombre de host debe estar en CN RDN del DN del sujeto de este certificado.

Cuestiones relacionadas