103 votes

Connexion Https Android

Je fais un post https et je reçois une exception de ssl exception Not trusted server certificate. Si je fais un http normal, cela fonctionne parfaitement bien. Dois-je accepter le certificat du serveur d'une manière ou d'une autre ?

0 votes

Puis-je obtenir un exemple de mise en œuvre de la même chose ?

0 votes

Ce fil de discussion peut aider, mais je ne peux pas dire si cela fonctionne avec la dernière API : groups.google.com/group/Android-developers/browse_thread/thread/

94voto

Ulrich Scheller Points 5144

C'est ce que je fais. Il ne vérifie simplement plus le certificat.

// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

/**
 * Trust every server - dont check for any certificate
 */
private static void trustAllHosts() {
    // Create a trust manager that does not validate certificate chains
    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 {
        }
    } };

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection
                .setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

y

    HttpURLConnection http = null;

    if (url.getProtocol().toLowerCase().equals("https")) {
        trustAllHosts();
        HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
        https.setHostnameVerifier(DO_NOT_VERIFY);
        http = https;
    } else {
        http = (HttpURLConnection) url.openConnection();
    }

0 votes

Cela semble bien ! Cependant, j'utilise WebView et j'ai seulement besoin de me connecter à un serveur https à des fins de test. (Le client ne peut pas en provisionner un avec un FQDN correspondant, ni tester en http). Existe-t-il un moyen de résoudre ce problème en utilisant WebView ? Est-ce que je dois simplement déposer ce code dans l'activité où se trouve le WebView et "ça marche" ? (Je ne pense pas ? ??)

0 votes

J'essaie d'utiliser cette solution étape par étape et j'obtiens cette exception : 07-25 12:35:25.941 : WARN/System.err(24383) : java.lang.ClassCastException : org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl à l'endroit où j'essaie d'ouvrir une connexion... une idée de la raison ?

1 votes

J'ai fait ce que vous avez suggéré mais j'obtiens l'exception suivante javax.net.ssl.SSLException: Received fatal alert: bad_record_mac . J'ai également essayé de remplacer TLS con SSL mais cela ne m'a pas aidé. Merci de m'aider.

45voto

Nate Points 2100

Je ne fais que supposer, mais si vous voulez qu'une véritable poignée de main se produise, vous devez informer Android de votre certificat. Si vous voulez juste accepter quoi qu'il arrive, alors utilisez ce pseudo-code pour obtenir ce dont vous avez besoin avec le client HTTP Apache :

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 est une classe qui implémente javax.net.ssl.X509TrustManager, mais aucune de ses méthodes n'effectue de travail, obtenez un échantillon. aquí .

Bonne chance !

0 votes

Pourquoi y a-t-il la variable FACTORY ??

0 votes

Clarifié dans le post. Vous avez besoin de FACTORY pour les autres méthodes qu'un SocketFactory doit utiliser pour créer une socket.

1 votes

Return FACTORY.createSocket() ; a un problème. La socket créée donne une exception de type null Pointer lors de la commande execute(). De plus, j'ai remarqué qu'il existe 2 classes SocketFactory. 1. org.apache.http.conn.ssl.SSLSocketFactory et 2. javax.net.ssl.SSLSocketFactory.

33voto

bajohns Points 636

En essayant de répondre à cette question, j'ai trouvé un meilleur tutoriel. Avec lui, vous n'avez pas à compromettre la vérification du certificat.

http://blog.crazybob.org/2010/02/Android-trusting-ssl-certificates.html

*Je n'ai pas écrit ce texte, mais merci à Bob Lee pour son travail.

4 votes

C'est la réponse parfaite. J'ai fait un post de mise à jour qui montre comment traiter les CA non listés car je recevais une erreur PeerCertificate. Voir ici : blog.donnfelker.com/2011/06/13/

6voto

saxos Points 1494

Vous pouvez également consulter l'article de mon blog, très similaire à celui de crazybobs.

Cette solution ne compromet pas non plus la vérification des certificats et explique comment ajouter les certificats de confiance dans votre propre keystore.

http://blog.antoine.li/index.php/2010/10/Android-trusting-ssl-certificates/

4voto

rohit mandiwal Points 4883

http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html

Avec l'aimable autorisation de Maduranga

Lorsque vous développez une application qui utilise https, votre serveur de test ne dispose pas d'un certificat SSL valide. Ou parfois le site web utilise un certificat auto-signé ou le site web utilise un certificat SSL gratuit. Donc si vous essayez de vous connecter au serveur en utilisant Apache HttpClient vous obtiendrez une exception indiquant que le "peer not authenticated". Bien que ce ne soit pas une bonne pratique de faire confiance à tous les certificats dans un logiciel de production, vous pouvez avoir à le faire en fonction de la situation. Cette solution résout l'exception causée par "peer not authenticated".

Mais avant de passer à la solution, je dois vous avertir que ce n'est pas une bonne idée pour une application de production. Cela violerait l'objectif de l'utilisation d'un certificat de sécurité. Donc, à moins que vous n'ayez une bonne raison ou que vous soyez sûr que cela ne posera aucun problème, n'utilisez pas cette solution.

Normalement, vous créez un HttpClient comme ça.

HttpClient httpclient = new DefaultHttpClient();

Mais vous devez modifier la façon dont vous créez le HttpClient.

Tout d'abord, vous devez créer une classe étendant org.apache.http.conn.ssl.SSLSocketFactory .

import org.apache.http.conn.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class MySSLSocketFactory extends SSLSocketFactory {
         SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

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

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

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

Créez ensuite une méthode comme celle-ci.

public HttpClient getNewHttpClient() {
     try {
         KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
         trustStore.load(null, null);

         SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
         sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

         HttpParams params = new BasicHttpParams();
         HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
         HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

         SchemeRegistry registry = new SchemeRegistry();
         registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
         registry.register(new Scheme("https", sf, 443));

         ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

         return new DefaultHttpClient(ccm, params);
     } catch (Exception e) {
         return new DefaultHttpClient();
     }
}

Ensuite, vous pouvez créer le HttpClient .

HttpClient httpclient = getNewHttpClient();

Si vous essayez d'envoyer une demande de courrier à une page de connexion, le reste du code sera le suivant.

private URI url = new URI("url of the action of the form");
HttpPost httppost =  new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();  
nameValuePairs.add(new BasicNameValuePair("username", "user"));  
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
    httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity entity = response.getEntity();
    InputStream is = entity.getContent();
} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ClientProtocolException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Vous récupérez la page html dans l'InputStream. Ensuite, vous pouvez faire ce que vous voulez avec la page html renvoyée.

Mais ici, vous allez rencontrer un problème. Si vous voulez gérer une session en utilisant des cookies, vous ne pourrez pas le faire avec cette méthode. Si vous voulez obtenir les cookies, vous devrez le faire via un navigateur. Vous serez alors le seul à recevoir des cookies.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X