java.io.IOException: nombre de host no verificado

Intento conectarme a una URL de una aplicación de mi Android en Andorid Version 4.1.1, y obtengo el error indicado en el título de mi pregunta, pero cuando bash conectar la misma URL desde Andorid Version 4.0.4 o 3.1 , todo funciona bien

El fragmento de código:

try { . . . URL url = new URL(urlStr); Log.i(TAG,"[ URL ] " + urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); int size = conn.getContentLength(); int responsecode = conn.getResponseCode(); Log.d(TAG, "Responsecode: " + responsecode); . . . } catch (Exception e) { e.printStackTrace(); } private static void trustAllHosts() { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[] {}; } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } } }; try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection .setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { System.out.println("IOException : HTTPSRequest::trustAllHosts"); e.printStackTrace(); } } 

Pero aquí aclaro una cosa es que “Tal vez el certificado es que los certificados autofirmados y no los incluye en una KeyStore.

No entiendo por qué ocurre esta excepción solo en Android Verison 4.1.1 OS Gracias.

RASTRO DE PILA COMPLETA

 01-31 10:26:08.348: W/System.err(3158): java.io.IOException: Hostname  was not verified 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223) 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446) 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:289) 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:239) 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:273) 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpURLConnectionImpl.getHeaderField(HttpURLConnectionImpl.java:130) 01-31 10:26:08.348: W/System.err(3158): at java.net.URLConnection.getHeaderFieldInt(URLConnection.java:544) 01-31 10:26:08.348: W/System.err(3158): at java.net.URLConnection.getContentLength(URLConnection.java:316) 01-31 10:26:08.348: W/System.err(3158): at libcore.net.http.HttpsURLConnectionImpl.getContentLength(HttpsURLConnectionImpl.java:191) 01-31 10:26:08.348: W/System.err(3158): at com.ih.util.HelpVideoServices$downloadTask.run(HelpVideoServices.java:172) 

En caso de que esté ejecutando certificados que no signifiquen nada y quiera omitirlos, también deberá agregar un verificador de nombre de host nulo para que este código funcione.

 HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier()); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new X509TrustManager[]{new NullX509TrustManager()}, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 

Y el código para el host:

 import javax.net.ssl.HostnameVerifier ; import javax.net.ssl.SSLSession; public class NullHostNameVerifier implements HostnameVerifier { @Override public boolean verify(String hostname, SSLSession session) { Log.i("RestUtilImpl", "Approving certificate for " + hostname); return true; } } 

Esto debe ejecutarse una vez, pero si realiza cambios en su objeto de conexión, es posible que deba ejecutarlo nuevamente.

Además de la respuesta de @Noam, este es un ejemplo completo:

 /** * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to * aid testing on a local box, not for use on production. */ private static void disableSSLCertificateChecking() { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { // not implemented } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { // not implemented } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } } }; try { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }); SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } 

Espero eso ayude

Esto podría suceder porque el CN ​​(Nombre común) que ha declarado en su SSL no afecta a la URL real a la que está enviando su solicitud HTTP.

Si es así, cree un nuevo SSL e ingrese el CN ​​correcto. Eso debería arreglar el problema.

Experimenté este problema en 4.1.1 y 4.1.2, usando HTTPSUrlConnection.

Después de hurgar, descubrí que era porque el servidor Apache con el que tengo múltiples hosts virtuales que atienden el tráfico https, resulta en problemas de SNI en Android, al menos antes de JellyBean (tengo informes no confirmados de que estaba funcionando en JB).

En mi caso, había 3 servidores virtuales que servían el tráfico https:

  • mydomain.com
  • api.midominio.com (el que estaba tratando de resolver)
  • admin.midominio.com

Sonda api. * Con openssl_client como este:

 openssl s_client -debug -connect api.mydomain.com:443 

… siempre devolvió el certificado del dominio raíz – enterrado en la salida era algo así como:

 Certificate chain 0 s:/OU=Domain Control Validated/CN=mydomain.com ... 

… especificando el nombre del servidor en la línea de comando openssl_client:

 openssl s_client -debug -servername api.mydomain.com -connect api.mydomain.com:443 

… devolvió el certificado que esperaba ver:

 Certificate chain 0 s:/OU=Domain Control Validated/CN=api.mydomain.com 

Pude resolver el problema moviendo el dominio virtual host-raíz a un host físico diferente.

Parece que Android HostnameVerifier puede vivir con varios subdominios uno al lado del otro como hosts virtuales, pero tener el dominio raíz como un host virtual en el mismo apache causó problemas.

No soy un sys-admin / dev-ops, por lo que es posible que haya opciones de configuración de Apache que podrían haber resuelto el problema del que no tengo conocimiento.

Android no puede configurar una conexión SSL, supongo. Tal vez su certificado para otro nombre de host, no el que establece conexión. Lee los documentos aquí y aquí .

es posible que tu problema sea el que tu URL se resolvió a través de “https”. debes convertir todas las URL de cadena a “http” y funcionará.

EDITAR:

 SchemeRegistry schemeRegistry = new SchemeRegistry (); schemeRegistry.register (new Scheme ("http", PlainSocketFactory.getSocketFactory (), 80)); schemeRegistry.register (new Scheme ("https", new CustomSSLSocketFactory (), 443)); ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager ( params, schemeRegistry); return new DefaultHttpClient (cm, params); 

CustomSSLSocketFactory:

 public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory { private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory (); public CustomSSLSocketFactory () { super(null); try { SSLContext context = SSLContext.getInstance ("TLS"); TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () }; context.init (null, tm, new SecureRandom ()); FACTORY = context.getSocketFactory (); } catch (Exception e) { e.printStackTrace(); } } public Socket createSocket() throws IOException { return FACTORY.createSocket(); } // TODO: add other methods like createSocket() and getDefaultCipherSuites(). // Hint: they all just make a call to member FACTORY } 

FullX509TrustManager es una clase que implementa javax.net.ssl.X509TrustManager, pero ninguno de los métodos realmente realiza ningún trabajo, obtenga una muestra [aquí] [1].

¡Buena suerte!

Tenga en cuenta que el Certificado SSL solo funciona por Dominio y no funciona por dirección IP.

si usa IP, inserte el código siguiente

 HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { if(hostname.equals("127.0.0.1")) return true; } }); 

De la documentación de Amazon: Restricciones del paquete

“Al usar cubos de estilo alojado virtual con SSL, el certificado comodín SSL solo coincide con los cubos que no contienen períodos. Para solucionar esto, use HTTP o escriba su propia lógica de verificación de certificado”.

La forma más fácil parece crear un nombre único de cubo sin puntos:

En lugar de “bucketname.mycompany.com”, algo como “bucketnamemycompany” o cualquier otro nombre de bucket compatible con DNS.