Java.io.IOException: El nombre de host no se ha verificado

Estoy intentando conectarme a una URL desde una aplicación de Android en Andorid Versión 4.1.1, y obtengo el error indicado en el Título de mi pregunta, pero cuando intenté conectar la misma URL de Andorid Versión 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í una cosa clara es que "Tal vez el certificado es que los certificados auto-firmados y no está incluidos en un KeyStore.

No entiendo por qué este excepton occure sólo en Android Verison 4.1.1 OS Gracias.

TRAZO DE PILA COMPLETA

 01-31 10:26:08.348: W/System.err(3158): java.io.IOException: Hostname <URL> 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 se ejecuta con certificados que no significa nada y que desea omitir, también es necesario agregar un verificador de nombre de host nulo para hacer que este código de trabajo

 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 está realizando cambios en el objeto de conexión, es posible que necesite ejecutarlo de nuevo.

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 puede ocurrir porque el CN ​​(nombre común) que ha declarado en su SSL no es la URL real que está enviando su solicitud HTTP.

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

He experimentado este problema en 4.1.1 y 4.1.2, utilizando HTTPSUrlConnection.

Después de un poco de empuje alrededor descubrí que era porque el servidor de Apache que estoy tratando tiene varios hosts virtuales que sirven tráfico https, lo que resulta en problemas de SNI en Android – al menos antes de JellyBean (tengo informes no confirmados de que estaba trabajando en JB).

En mi caso había 3 hosts virtuales que sirven tráfico https:

  • Mydomain.com
  • Api.mydomain.com (el que estaba tratando de tratar)
  • Admin.mydomain.com

Probing api. * Con openssl_client como este:

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

… siempre devuelve 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 comandos 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 

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

Parece que el Android HostnameVerifier puede vivir con varios subdominios lado a lado como hosts virtuales, pero tener el dominio raíz como un host virtual en el mismo apache causado problemas.

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

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

Es posible que tu problema sea lo que tu URL se resolvió vía "https". Usted debe convertir todas las urls de la secuencia a "http" y trabajará.

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 realizar ningún trabajo, obtener una muestra [aquí] [1].

¡Buena suerte!

De la documentación de Amazon: Restricciones de cuchara

"Cuando se utiliza cubos virtuales de estilo alojado con SSL, el certificado de comodín SSL sólo coincide con cubos que no contienen períodos. Para evitar esto, utilice HTTP o escriba su propia lógica de verificación de certificados."

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

En lugar de "bucketname.mycompany.com", algo así como "bucketnamemycompany" o cualquier otro nombre de cubo compatible con DNS.

  • HttpURLConnection realiza siempre una solicitud GET en lugar de una solicitud POST a pesar de setDoOutput (true) y setRequestMethod ("POST")
  • Cómo hacer http obtener solicitud en Android
  • HttpGet params que no se envían
  • Cómo pausar una Httpurlconnection en android en el botón de clic
  • Cómo modificar los encabezados de solicitudes HTTP desde una aplicación de Android?
  • Enviar datos binarios a través de POST en android
  • Descargar archivos grandes desde android, con una recuperación por error
  • Cómo responder a los desafíos de autenticación HTTP en Android
  • Android desconocidoHostException Facebook SDK
  • Escanea tarjetas de negocios con Phonegap
  • Android: AndroidHttpClient - ¿cómo establecer el tiempo de espera?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.