Aceptar certificados SSL autofirmados-> donde configurar TrustManager predeterminado
Primero tuve que admitir que sé que aceptar todos los certificados puede ser considerado como sin seguridad. Tenemos Certs "reales" pero solamente en nuestros sistemas vivos. Los certificados en nuestros sistemas de prueba son auto-firmados. Así que mientras nos estamos desarrollando, tenemos que usar servidores de prueba, lo que me obliga a deshabilitar certificados.
Vi un montón de toppics aquí en Stackoverflow y en toda la web que están todos tratando de hacer lo mismo: Aceptación de certificados SSL. Sin embargo, ninguna de estas respuestas parece aplicarse a mi problema, ya que no estoy jugando con HTTPSUrlConnections
.
- ¿Es este android SSL pinning implementación correcta y por qué este error aparece en el logcat?
- Android - convertir la cadena de certificados pkcs12 al objeto de certificado x509 para bks keystore
- Cómo importar certificado SSL autofirmado a Volley en Android 4.1+
- Android manual X509 validación de la cadena de certificados
- Android KeyStore: Error al generar certificado autofirmado, cadena de fecha no válida
Si estoy haciendo una solicitud el código normalmente se parece a esto (comentado para la clarificación):
//creates an HTTP-Post with an URL HttpPost post = createBaseHttpPost(); //loads the request Data inside the httpPost post.setEntity(getHttpPostEntity()); //appends some Headers like user-agend or Request UUIDs appendHeaders(post); HttpClient client = new DefaultHttpClient(); //mResponse is a custom Object which is returned //from the custom ResponseHandler(mResponseHandler) mResponse = client.execute(post, mResponseHandler); return mResponse;
Leí que debo inyectar mi propio TrustManager
y X509HostnameVerivier
. Los he creado así:
private static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } } }; private static X509HostnameVerifier ACCEPT_ALL_HOSTNAMES = new X509HostnameVerifier() { public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { } public void verify(String host, X509Certificate cert) throws SSLException { } public void verify(String host, SSLSocket ssl) throws IOException { } public boolean verify(String host, SSLSession session) { return true; } };
Si me inyecto HostnameVerifier
dentro de mi solicitud como esta (el cliente es DefaultHttpClient desde arriba)
SSLSocketFactory ssl = (SSLSocketFactory)client.getConnectionManager().getSchemeRegistry().getScheme("https").getSocketFactory(); ssl.setHostnameVerifier(ACCEPT_ALL_HOSTNAMES);
La respuesta cambia de "hostname ** no coinciden" a "Bad request". Supongo que tengo que configurar el TrustManager, pero no tengo ni idea de dónde establecerlo dentro de mi solicitud, ya que no estoy usando HttpsUrlConnections mencionado en todas partes que lo busqué.
- ¿Cómo implementar la fijación de hojas / certificados intermedios en Android?
- ¿Cómo puedo validar un android.net.http.SsLCertificate con un X509TrustManager?
- Instalación del certificado autofirmado mediante programación
- Cómo abrir MIME - "application / x-509-server-cert" tipo en Android Moto G?
- ¿Cómo instalar mediante programación un certificado de CA (para configuración EAP WiFi) en Android?
- Agregar varios certificados SSL a Android KeyStore no funciona. (Desde el archivo de recursos)
- Mostrar certificado de Android
- ¿Cómo generamos un hash SHA256 codificado en base64 de SubjectPublicKeyInfo de un certificado X.509, para la fijación del certificado de Android N?
No, no te obliga a deshabilitar la validación, te obliga a implementar la validación correctamente. No acepte ciegamente todos los certificados. Y no, su caso no es diferente, sólo tiene que confiar en un certificado que Android no confía por defecto.
Está utilizando HttpClient, por lo que las API para configurar el administrador de confianza son algo diferentes de HttpsURLConnection
, pero el procedimiento es el mismo:
- Cargue un archivo de almacén de claves con certificados de confianza (los certificados autofirmados del servidor)
- Inicializar un
KeyStore
con él. - Cree un
SocketFactory
usando elKeyStore
de 2. - Establezca su biblioteca de cliente HTTP para usarla cuando cree sockets SSL.
Esto se describe en la documentación de Android: http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html
Un artículo más detallado sobre el tema, muestra cómo crear el archivo de almacén de confianza: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
Algunos antecedentes y código de ejemplo: http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
Este es el código que necesita para inicializar HttpClient:
KeyStore localTrustStore = KeyStore.getInstance("BKS"); InputStream in = getResources().openRawResource(R.raw.mytruststore); localTrustStore.load(in, TRUSTSTORE_PASSWORD.toCharArray()); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); SSLSocketFactory sslSocketFactory = new SSLSocketFactory(localTrustStore); schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); HttpParams params = new BasicHttpParams(); ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); HttpClient client = new DefaultHttpClient(cm, params);
En este punto, no tienes excusas para confiar en todos los certificados. Si lo haces, todo en ti 🙂
- JAVA_HOME se establece en un directorio no válido mientras se ejecuta ./gradlew en OSX
- Mostrar la vista de la imagen en la barra de herramientas de Android en la esquina superior izquierda antes del título