OkHttp javax.net.ssl.SSLPeerUnverifiedException: nombre de host dominio.com no verificado
⏰ 8 minutos de lectura
Llevo días intentando que esto funcione. Estoy tratando de conectarme a mi servidor a través de https con un certificado autofirmado. No creo que haya páginas o ejemplos que no haya leído hasta ahora.
Usa openssl s_client -connect domain.com:443 para obtener el certificado del servidor. Luego crea un almacén de claves bks usando un castillo hinchable.
Leer el almacén de claves creado desde la carpeta sin procesar, agregarlo a sslfactory y luego a OkHttpClient. Me gusta esto:
Esto por alguna razón esto siempre genera un SSLPeerUnverifiedException con o sin el almacén de claves. Y con o sin el CertificatePinner.
javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com not verified: 0
W/System.err﹕ certificate: sha1/theSha=
W/System.err﹕ DN: 1.2.840.113549.1.9.1=#1610696e666f40626561646963742e636f6d,CN=http://domain.com,OU=development,O=domain,L=Valencia,ST=Valencia,C=ES
W/System.err﹕ subjectAltNames: []
W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:124)
W/System.err﹕ at com.squareup.okhttp.Connection.connect(Connection.java:143)
W/System.err﹕ at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
W/System.err﹕ at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
W/System.err﹕ at com.squareup.okhttp.Call.getResponse(Call.java:273)
W/System.err﹕ at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230)
W/System.err﹕ at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201)
W/System.err﹕ at com.squareup.okhttp.Call.execute(Call.java:81)
...
¿Qué estoy haciendo mal?
Verifique que su certificado contenga el nombre de host real y no la dirección IP (se supone que las direcciones IP deben estar en Subject Alternative Name campo del certificado). Como para HostnameVerifier que devuelve verdadero: hará que SSL sea inútil e inseguro (la respuesta más votada). En los Android contemporáneos, puede instalar su certificado autofirmado sin problemas a través de la configuración de Seguridad.
– Boris Treukhov
6 de julio de 2016 a las 9:59
Tuve el mismo problema; sin embargo, necesitaba que mi aplicación funcionara en varios entornos de ensayo, todos los cuales tenían certificados autofirmados. Para empeorar las cosas, podrían cambiar esos certificados sobre la marcha.
Para solucionar esto, cuando me conectaba solo a la etapa de ensayo, agregué un SSLSocketFactory que confiaba en todos los certificados. Esto solucionó el error de Java, sin embargo, me dejó con la excepción okhttp anotada en este ticket.
Para evitar este error, necesitaba agregar una personalización más a mi okHttpClient. Esto solucionó el error para mí.
¡Esto no es seguro! Sé que no especifiqué eso en mi pregunta. Sé que funciona, lo he usado antes. Pero ahora soy un adulto y quiero la seguridad total de https. 🙂
– solo_usuario
12/09/2016 a las 10:21
por supuesto, esto no es seguro; esto omite explícitamente la verificación del certificado https. Esto solo debe usarse en entornos previos a la producción en los que desea evitar la verificación SSL, nunca en una compilación de producción.
– Jake Pasillo
13/09/2016 a las 21:28
setHostnameVerifier no compilar
– Lavekush Agrawal
06/07/2017 a las 10:00
setHostnameVerifier() no es un método de OkHttpCliente. Creo que lo estás confundiendo con javax.net.ssl.HttpsURLConnection
–Mike Harris
6 de marzo de 2019 a las 16:52
Gracias. me ayudó a deshacerme del error y hacer mis pruebas en depuración
– Reza
19 de agosto de 2020 a las 17:48
solo_usuario
Finalmente conseguí que esto funcionara con una combinación de múltiples respuestas.
Primero, los certificados se hicieron incorrectamente, no estoy seguro de cómo. Pero al crearlos usando el script en esta respuesta, los hizo funcionar. Lo que se necesitaba era un certificado de servidor y una clave. Entonces el cliente necesitaba otro certificado.
Para usar el certificado en Android, convertí el archivo .pem en un archivo .crt como este:
openssl x509 -outform der -in client.pem -out client.crt
En Android, agregué el certificado a mi cliente OkHttp de la siguiente manera:
La última parte con new AdditionalKeyStore() está tomado de esta respuesta muy bien escrita. Lo que agrega un almacén de claves alternativo.
¡Espero que esto pueda ayudar a alguien más! Esta es la forma más sencilla de hacer que HTTPS funcione con un certificado autofirmado que he encontrado. Otras formas incluyen tener un almacén de claves BouncyCastle que me parece excesivo.
¿Cuál es el archivo (cliente) en bruto?
– iSrinivasan27
12 de septiembre de 2016 a las 7:33
eso es el client.crtarchivo generado en la línea openssl.
– solo_usuario
12 de septiembre de 2016 a las 10:19
¿Cuál es el archivo client.pem que ha utilizado aquí? Ese script genera pocos archivos .pem. ¿Es el archivo chain.pem en el directorio del cliente?
¿Qué tan seguro es esto? Si devuelve verdadero, ¿no se aceptan todos los certificados? Si es así, ¡debería evitarse!
– solo_usuario
13 de septiembre de 2016 a las 6:41
Estoy de acuerdo @just_user. Esto funciona, pero no es una buena solución. Derecha…?
– Otziii
9 de agosto de 2017 a las 11:14
@Otziii Sí, esto no es seguro. No sé por qué la gente sigue sugiriendo esta “solución”. Verifique mi respuesta anterior, esto proporciona una opción más segura.
– solo_usuario
21 de agosto de 2017 a las 8:07
Eso me ayudó mucho. ¡Gracias!
– Javad Khan
24 de agosto de 2017 a las 6:53
Verifique si el nombre CN en el certificado del cliente se agrega al nombre alternativo del Sujeto. yo tuve el mismo problema
qrtls
Durante la generación del certificado, el subjectAltName debe establecerse si el uri es una ip para no fallar en la validación.
“En algunos casos, el URI se especifica como una dirección IP en lugar de un nombre de host. En este caso, el IPAddress subjectAltName debe estar presente en el certificado y debe coincidir exactamente con la IP en el URI”. RFC (mencionado por Bas en el comentario)
En lugar de jugar con el lado del cliente HostnameVerifier o bien, reiusse el certificado autofirmado (sobre el cual tenemos control) a través de:
Complemento, si en Android uno también necesita confiar en el certificado:
the crt is pem format and can be imported into android via
<?xml version="1.0" encoding="utf-8"?>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="@raw/nginx_selfsigned2" />
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
Por lo tanto, verificamos que el certificado proviene de una fuente confiable y, previamente, mediante la verificación del nombre de host (a través de SAN), nos aseguramos de que el servidor con el que hablamos presente el certificado correcto para su IP.
si eres usado network_security_config en res/xml para resolver Cleartext HTTP traffic not permitted y cambiaste de dominio/dirección IP recuerda que debes cambiar includeSubdomains valor a la nueva dirección. Esto funcionó para mí.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
Verifique que su certificado contenga el nombre de host real y no la dirección IP (se supone que las direcciones IP deben estar en
Subject Alternative Name
campo del certificado). Como paraHostnameVerifier
que devuelve verdadero: hará que SSL sea inútil e inseguro (la respuesta más votada). En los Android contemporáneos, puede instalar su certificado autofirmado sin problemas a través de la configuración de Seguridad.– Boris Treukhov
6 de julio de 2016 a las 9:59