aceptar conexiones HTTPS con certificados autofirmados


153

Estoy tratando de hacer conexiones HTTPS, usando HttpClientlib, pero el problema es que, dado que el certificado no está firmado por una Autoridad de certificación (CA) reconocida como Verisign , GlobalSIgn , etc., que figura en el conjunto de Certificados de confianza de Android, Sigo recibiendo javax.net.ssl.SSLException: Not trusted server certificate.

He visto soluciones en las que simplemente acepta todos los certificados, pero ¿qué pasa si quiero preguntarle al usuario?

Quiero obtener un cuadro de diálogo similar al del navegador, permitiendo que el usuario decida continuar o no. Preferiblemente me gustaría usar el mismo almacén de certificados que el navegador. ¿Algunas ideas?


Esta solución aceptada funcionó para mí- stackoverflow.com/questions/2642777/…
Venkatesh

Respuestas:


171

Lo primero que debe hacer es establecer el nivel de verificación. Tales niveles no son tanto:

  • ALLOW_ALL_HOSTNAME_VERIFIER
  • BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
  • STRICT_HOSTNAME_VERIFIER

Aunque el método setHostnameVerifier () es obsoleto para la nueva biblioteca apache, pero para la versión en Android SDK es normal. Y así lo tomamos ALLOW_ALL_HOSTNAME_VERIFIERy lo configuramos en la fábrica de métodos SSLSocketFactory.setHostnameVerifier().

A continuación, debe configurar nuestra fábrica para que el protocolo sea https. Para hacer esto, simplemente llame al SchemeRegistry.register()método.

Entonces necesitas crear un DefaultHttpClientcon SingleClientConnManager. También en el código a continuación puede ver que, por defecto, también usará nuestra bandera ( ALLOW_ALL_HOSTNAME_VERIFIER) por el métodoHttpsURLConnection.setDefaultHostnameVerifier()

El siguiente código funciona para mí:

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient client = new DefaultHttpClient();

SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

// Set verifier     
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

// Example send http request
final String url = "https://encrypted.google.com/";
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);

66
Lamentablemente, no puedo hacer que este código funcione, sigo recibiendo el "Certificado de servidor no confiable". ¿Hay algún permiso adicional que deba establecer para que funcione?
Juriy

1
¿Este código no solo acepta todos los certificados? Necesito una ventana emergente para aceptarlo.
Morten

3
Estoy usando org.apache.http.conn.ssl.SSLSocketFactory¿por qué quiero usar javax.net.ssl.HttpsURLConnection?
Alguien en alguna parte

9
¿Puede explicar cómo este código es mejor que deshabilitar por completo la verificación del certificado? No estoy familiarizado con la API SSL de Android, pero de un vistazo esto parece completamente inseguro contra los atacantes activos.
CodesInChaos

3
Sugeriría usar ThreadSafeClientConnManager en lugar de SingleClientConnManager
Granja

124

Los siguientes pasos principales son necesarios para lograr una conexión segura de las Autoridades de certificación que la plataforma de Android no considera de confianza.

Como lo solicitaron muchos usuarios, he reflejado las partes más importantes de mi artículo de blog aquí:

  1. Tome todos los certificados requeridos (raíz y cualquier CA intermedia)
  2. Cree un almacén de claves con keytool y el proveedor BouncyCastle e importe los certificados
  3. Cargue el almacén de claves en su aplicación de Android y úselo para las conexiones seguras (recomiendo usar el HttpClient de Apache en lugar del estándar java.net.ssl.HttpsURLConnection(más fácil de entender, más eficiente)

Agarra los certs

Debe obtener todos los certificados que crean una cadena desde el certificado de punto final hasta la CA raíz. Esto significa que cualquier certificado de CA intermedio (si está presente) y también el certificado de CA raíz. No necesita obtener el certificado de punto final.

Crea el almacén de claves

Descargue el proveedor BouncyCastle y guárdelo en una ubicación conocida. Asegúrese también de que puede invocar el comando keytool (generalmente ubicado debajo de la carpeta bin de su instalación de JRE).

Ahora importe los certificados obtenidos (no importe el certificado de punto final) en un almacén de claves con formato BouncyCastle.

No lo probé, pero creo que el orden de importación de los certificados es importante. Esto significa, primero importe el certificado de CA intermedio más bajo y luego hasta el certificado de CA raíz.

Con el siguiente comando , se creará un nuevo almacén de claves (si aún no está presente) con la contraseña mysecret y se importará el certificado CA intermedio. También definí el proveedor BouncyCastle, donde se puede encontrar en mi sistema de archivos y el formato del almacén de claves. Ejecute este comando para cada certificado en la cadena.

keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Verifique si los certificados se importaron correctamente en el almacén de claves:

keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Debería dar salida a toda la cadena:

RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Ahora puede copiar el almacén de claves como recurso sin procesar en su aplicación de Android en res/raw/

Usa el almacén de claves en tu aplicación

En primer lugar, tenemos que crear un HttpClient de Apache personalizado que use nuestro almacén de claves para conexiones HTTPS:

import org.apache.http.*

public class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
        this.context = context;
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        // Register for port 443 our SSLSocketFactory with our keystore
        // to the ConnectionManager
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".toCharArray());
            } finally {
                in.close();
            }
            // Pass the keystore to the SSLSocketFactory. The factory is responsible
            // for the verification of the server certificate.
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            // Hostname verification from certificate
            // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
            sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

Hemos creado nuestro HttpClient personalizado, ahora podemos usarlo para conexiones seguras. Por ejemplo, cuando hacemos una llamada GET a un recurso REST:

// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();

Eso es ;)


8
Esto solo es útil para obtener certificados antes de enviar su solicitud. Realmente no ayuda a los usuarios a aceptar sus propios certificados. para su aplicación
Fuzzy

Hola, ¿alguien puede decirme el proceso de validación para el almacén de claves con el almacén de confianza para la implementación anterior? gracias de antemano ..
andriod_testing 02 de

Esto funcionó bien ... pero ahora estoy enfrentando un problema cuando reescribo el certificado en el servidor. Parece extraño que cada vez que actualice el certificado en mi servidor, la tienda del lado del cliente también debería actualizarse. Tiene que haber una mejor manera: |
bpn

Respuesta de Gr8, sugeriría usar ThreadSafeClientConnManager en lugar de SingleClientConnManager
Granja

He agregado /res/raw/mykeystore.bks, aunque no puedo resolver la referencia a él. ¿Cómo resolver esto?
uniruddh

16

Si tiene un certificado personalizado / autofirmado en el servidor que no está en el dispositivo, puede usar la siguiente clase para cargarlo y usarlo en el lado del cliente en Android:

Coloque el *.crtarchivo del certificado /res/rawpara que esté disponible enR.raw.*

Use la clase a continuación para obtener un HTTPCliento HttpsURLConnectionque tendrá una fábrica de sockets utilizando ese certificado:

package com.example.customssl;

import android.content.Context;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

public class CustomCAHttpsProvider {

    /**
     * Creates a {@link org.apache.http.client.HttpClient} which is configured to work with a custom authority
     * certificate.
     *
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http Client.
     * @throws Exception If there is an error initializing the client.
     */
    public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {


        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // init ssl socket factory with key store
        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);

        // skip hostname security check if specified
        if (allowAllHosts) {
            sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        // basic http params for client
        HttpParams params = new BasicHttpParams();

        // normal scheme registry with our ssl socket factory for "https"
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

        // create connection manager
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);

        // create http client
        return new DefaultHttpClient(cm, params);
    }

    /**
     * Creates a {@link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
     * certificate.
     *
     * @param urlString     remote url string.
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http url connection.
     * @throws Exception If there is an error initializing the connection.
     */
    public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
                                                           boolean allowAllHosts) throws Exception {

        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        // Create a connection from url
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

        // skip hostname security check if specified
        if (allowAllHosts) {
            urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        return urlConnection;
    }

    private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
        // init a default key store
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);

        // read and add certificate authority
        Certificate cert = readCert(context, certRawResId);
        keyStore.setCertificateEntry("ca", cert);

        return keyStore;
    }

    private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {

        // read certificate resource
        InputStream caInput = context.getResources().openRawResource(certResourceId);

        Certificate ca;
        try {
            // generate a certificate
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ca = cf.generateCertificate(caInput);
        } finally {
            caInput.close();
        }

        return ca;
    }

}

Puntos clave:

  1. CertificateLos objetos se generan a partir de .crtarchivos.
  2. Se KeyStorecrea un valor predeterminado .
  3. keyStore.setCertificateEntry("ca", cert)está agregando un certificado al almacén de claves con el alias "ca". Modifica el código para agregar más certificados (CA intermedia, etc.).
  4. El objetivo principal es generar un SSLSocketFactoryque luego puede ser utilizado por HTTPCliento HttpsURLConnection.
  5. SSLSocketFactory se puede configurar más, por ejemplo, para omitir la verificación del nombre de host, etc.

Más información en: http://developer.android.com/training/articles/security-ssl.html


¿Dónde puedo obtener .crtarchivos? ¿Descargar desde un servidor?
zionpi

@zionpi El archivo de certificado será el mismo utilizado por el servidor habilitado para TLS al que se está conectando.
SD

¡Gracias! ¡Esto fue muy fácil!
kapil thadani

@SD ¿Cómo puedo usar el archivo .P12 en lugar de .crt?
Rakesh R Nair

Tengo una duda similar fría, por favor ayuda stackoverflow.com/questions/57389622/…
StezPet

8

Estaba frustrado al intentar conectar mi aplicación de Android a mi servicio RESTful usando https. También estaba un poco molesto por todas las respuestas que sugerían desactivar la verificación de certificados por completo. Si lo haces, ¿cuál es el punto de https?

Después de buscar en Google el tema por un tiempo, finalmente encontré esta solución donde no se necesitan frascos externos, solo API de Android. Gracias a Andrew Smith, quien lo publicó en julio de 2014.

 /**
 * Set up a connection to myservice.domain using HTTPS. An entire function
 * is needed to do this because myservice.domain has a self-signed certificate.
 * 
 * The caller of the function would do something like:
 * HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
 * InputStream in = urlConnection.getInputStream();
 * And read from that "in" as usual in Java
 * 
 * Based on code from:
 * https://developer.android.com/training/articles/security-ssl.html#SelfSigned
 */
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
    try
    {
        // Load CAs from an InputStream
        // (could be from a resource or ByteArrayInputStream or ...)
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        // My CRT file that I put in the assets folder
        // I got this file by following these steps:
        // * Go to https://littlesvr.ca using Firefox
        // * Click the padlock/More/Security/View Certificate/Details/Export
        // * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
        // The MainActivity.context is declared as:
        // public static Context context;
        // And initialized in MainActivity.onCreate() as:
        // MainActivity.context = getApplicationContext();
        InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
        Certificate ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        // Tell the URLConnection to use a SocketFactory from our SSLContext
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());

        return urlConnection;
    }
    catch (Exception ex)
    {
        Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
        return null;
    }
}

Funcionó bien para mi aplicación de maqueta.


X509Certificate ¿cuál debo importar java o javax?
Siddharth el

Importéimport java.security.cert.X509Certificate;
Gonzalo Fernández

Gracias por esto. Es realmente trabajo y simple
Anuradhe Dilshan

6

La respuesta principal no me funcionó. Después de investigar un poco, encontré la información requerida sobre "Desarrollador de Android": https://developer.android.com/training/articles/security-ssl.html#SelfSigned

Crear una implementación vacía de X509TrustManager hizo el truco:

private static class MyTrustManager implements X509TrustManager
{

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
         throws CertificateException
    {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers()
    {
        return null;
    }

}

...

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    TrustManager[] tmlist = {new MyTrustManager()};
    context.init(null, tmlist, null);
    conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
    throw new IOException(e);
} catch (KeyManagementException e)
{
    throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();

¡Tenga en cuenta que esta implementación vacía de TustManager es solo un ejemplo y su uso en un entorno productivo podría causar una grave amenaza de seguridad!


1
solo digo - idk si era así en ese momento, pero parecen desalentar fuertemente este enfoque ahora (ver la nota)
Saik Caskey

6

Google recomienda el uso de Android Volley para conexiones HTTP / HTTPS , ya que HttpClientestá en desuso. Entonces, sabes la elección correcta :).

Y también, NUNCA NUKE Certificados SSL (NUNCA !!!).

Nukear los certificados SSL es totalmente contrario al propósito de SSL, que es promover la seguridad . No tiene sentido usar SSL, si planea bombardear todos los certificados SSL que vienen. Una mejor solución sería, no usar SSL, o una mejor solución, sería crear una aplicación personalizada TrustManageren su aplicación + usando Android Volley para conexiones HTTP / HTTPS.

Aquí hay un Gist que creé, con una aplicación de inicio de sesión básica, que realiza conexiones HTTPS, usando un certificado autofirmado en el lado del servidor, aceptado en la aplicación.

Aquí también hay otro Gist que puede ayudar, para crear certificados SSL autofirmados para configurar en su servidor y también usar el certificado en su aplicación. Muy importante: debe copiar el archivo .crt que fue generado por la secuencia de comandos anterior, al directorio "en bruto" de su proyecto de Android.


Hola Ivan, nunca he trabajado con certificados SSL. ¿Le gustaría elaborar un poco, cómo obtengo el archivo .crt?
Jlively

Hola jively Veo. Sí, por supuesto. Pero primero, ¿le importaría echar un vistazo al segundo Gist que mencioné anteriormente? Puse dos archivos en este Gist: uno es el archivo utilizado por el script y el otro, es el script en sí mismo, que usa el binario "openssl" para leer el archivo y luego, construir el archivo que contiene el Certificado SSL ( .crt). Avísame si lograste entenderlo todo. Saludos :).
ivanleoncz

Hmm, sí, he visto esas 2 claves, pero realmente no puedo entender cómo las uso.
Jlively

4

Aquí le mostramos cómo puede agregar certificados adicionales a su KeyStore para evitar este problema: Confiar en todos los certificados usando HttpClient sobre HTTPS

No le preguntará al usuario como usted pregunta, pero hará que sea menos probable que el usuario se encuentre con un error de "Certificado de servidor no confiable".


Solo con fines de prueba, no puedes publicar una aplicación en Play Store con este truco porque será rechazada
ariel

3

La forma más sencilla de crear un certificado SSL

Abra Firefox (supongo que también es posible con Chrome, pero es más fácil para mí con FF)

Visite su sitio de desarrollo con un certificado SSL autofirmado.

Haga clic en el certificado (al lado del nombre del sitio)

Haga clic en "Más información"

Haga clic en "Ver certificado"

Haga clic en "Detalles"

Haga clic en "Exportar ..."

Elija "Certificado X.509 con cadena (PEM)", seleccione la carpeta y el nombre para guardarlo y haga clic en "Guardar"

Vaya a la línea de comando, al directorio donde descargó el archivo pem y ejecute "openssl x509 -inform PEM -outform DM -in .pem -out .crt"

Copie el archivo .crt en la raíz de la carpeta / sdcard dentro de su dispositivo Android Dentro de su dispositivo Android, Configuración> Seguridad> Instalar desde el almacenamiento.

Debería detectar el certificado y permitirle agregarlo al dispositivo. Navegue a su sitio de desarrollo.

La primera vez debería pedirle que confirme la excepción de seguridad. Eso es todo.

El certificado debería funcionar con cualquier navegador instalado en su Android (navegador, Chrome, Opera, Dolphin ...)

Recuerde que si está sirviendo sus archivos estáticos desde un dominio diferente (todos somos perras de velocidad de página) también debe agregar el certificado para ese dominio.


2

Escribí una pequeña biblioteca ssl-utils-android para confiar en un certificado particular en Android.

Simplemente puede cargar cualquier certificado dando el nombre del archivo desde el directorio de activos.

Uso:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

1

Ninguna de estas soluciones funcionó para mi plataforma de desarrollo dirigida al SDK 16, versión 4.1.2, por lo que encontré una solución.

Mi aplicación almacena datos en el servidor usando " http://www.example.com/page.php?data=somedata "

Recientemente, page.php se movió a " https://www.secure-example.com/page.php " y sigo recibiendo "javax.net.ssl.SSLException: Certificado de servidor no confiable".

En lugar de aceptar todos los certificados para una sola página, comenzando con esta guía , resolví mi problema escribiendo mi propia página.php publicada en " http://www.example.com/page.php "

<?php

caronte ("https://www.secure-example.com/page.php");

function caronte($url) {
    // build curl request
    $ch = curl_init();
    foreach ($_POST as $a => $b) {
        $post[htmlentities($a)]=htmlentities($b);
    }
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));

    // receive server response ...
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $server_output = curl_exec ($ch);
    curl_close ($ch);

    echo $server_output;
}

?>

1

19 de enero de 2020 Certificado autofirmado PROBLEMA:

Para reproducir video, imagen, llamar al servicio web para obtener un certificado autofirmado o conectarse a una URL no segura, simplemente llame a este método antes de realizar cualquier acción, solucionará su problema relacionado con el problema del certificado:

CÓDIGO KOTLIN

  private fun disableSSLCertificateChecking() {
        val hostnameVerifier = object: HostnameVerifier {
            override fun verify(s:String, sslSession: SSLSession):Boolean {
                return true
            }
        }
        val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
            override fun getAcceptedIssuers(): Array<X509Certificate> {
                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }

            //val acceptedIssuers:Array<X509Certificate> = null
            @Throws(CertificateException::class)
            override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
            }
            @Throws(CertificateException::class)
            override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
            }
        })
        try
        {
            val sc = SSLContext.getInstance("TLS")
            sc.init(null, trustAllCerts, java.security.SecureRandom())
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
            HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
        }
        catch (e: KeyManagementException) {
            e.printStackTrace()
        }
        catch (e: NoSuchAlgorithmException) {
            e.printStackTrace()
        }
    }

0

Tal vez esto sea útil ... funciona en clientes Java utilizando certificados autofirmados (no hay verificación del certificado). ¡Tenga cuidado y úselo solo para casos de desarrollo porque eso no es seguro en absoluto!

Cómo ignorar los errores de certificado SSL en Apache HttpClient 4.0

Espero que funcione en Android solo agregando la biblioteca HttpClient ... ¡buena suerte!


1
No, no funciona en Android, ya que se basa en métodos obsoletos que no están presentes en la variante de Android :-(
kellyfj

0

Este es un problema resultante de la falta de compatibilidad con SNI (Identificación de nombre de servidor) en A, ndroid 2.x. Estuve luchando con este problema durante una semana hasta que me encontré con la siguiente pregunta, que no solo brinda un buen historial del problema, sino que también proporciona una solución eficaz y funcional sin ningún agujero de seguridad.

Error 'Sin certificado de igual' en Android 2.3 pero NO en 4

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.