web-dev-qa-db-fra.com

Https Connection Android

Je fais un post https et j'obtiens une exception d'exception ssl. Certificat de serveur non approuvé. Si je fais http normal cela fonctionne parfaitement bien. Dois-je accepter le certificat de serveur d'une manière ou d'une autre?

97
Sam97305421562

Je fais une supposition, mais si vous voulez une poignée de main, vous devez informer Android de votre certificat. Si vous voulez simplement accepter n'importe quoi, 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 des méthodes n'effectue de travail, obtenez un exemple ici .

Bonne chance!

45
Nate

C'est ce que je fais. Il ne vérifie tout 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();
    }
}

et

    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();
    }
83
Ulrich Scheller

En essayant de répondre à cette question, j'ai trouvé un meilleur tutoriel. Avec cela, 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 ça mais merci à Bob Lee pour le travail

33
bajohns

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

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

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

6
saxos

Si vous utilisez un certificat StartSSL ou Thawte, il échouera pour Froyo et les versions antérieures. Vous pouvez utiliser un référentiel CAcert de la version plus récente } au lieu de faire confiance à chaque certificat.

3
Juan Sánchez

Aucune de ces choses n'a fonctionné pour moi (aggravée par le bug Thawte aussi). J'ai finalement résolu le problème avec Acceptation SSL auto-signée sur Android et La gestion SSL personnalisée a cessé de fonctionner sur Android 2.2 FroYo

2
Adrian Spinei

Aucune de ces réponses n'a fonctionné pour moi alors voici un code qui fait confiance aux certificats.

import Java.io.IOException;

    import Java.net.Socket;
    import Java.security.KeyManagementException;
    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;

    import org.Apache.http.client.ClientProtocolException;
    import org.Apache.http.client.HttpClient;
    import org.Apache.http.client.methods.HttpPost;
    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.SSLSocketFactory;
    import org.Apache.http.conn.ssl.X509HostnameVerifier;
    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.HttpConnectionParams;
import org.Apache.http.params.HttpParams;

    public class HttpsClientBuilder {
        public static DefaultHttpClient getBelieverHttpsClient() {

            DefaultHttpClient client = null;

            SchemeRegistry Current_Scheme = new SchemeRegistry();
            Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            try {
                Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443));
            } catch (KeyManagementException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnrecoverableKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (KeyStoreException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            HttpParams Current_Params = new BasicHttpParams();
            int timeoutConnection = 8000;
            HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection);
            int timeoutSocket = 10000;
            HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket);
            ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme);
            client = new DefaultHttpClient(Current_Manager, Current_Params);
            //HttpPost httpPost = new HttpPost(url);
            //client.execute(httpPost);

         return client;
         }

    public static class Naive_SSLSocketFactory extends SSLSocketFactory
    {
        protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS");

        public Naive_SSLSocketFactory ()
                throws NoSuchAlgorithmException, KeyManagementException,
                KeyStoreException, UnrecoverableKeyException
        {
            super(null, null, null, null, null, (X509HostnameVerifier)null);
            Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null);
        }

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

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

    private static class X509_Trust_Manager implements X509TrustManager
    {

        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            // TODO Auto-generated method stub

        }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            // TODO Auto-generated method stub

        }

        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }

    };
}
2
Speise

C'est un problème connu sous Android 2.x. Je me débattais avec ce problème pendant une semaine jusqu'à ce que je tombe sur la question suivante, qui non seulement donne un bon fond du problème, mais fournit également une solution efficace et dépourvue de faille de sécurité.

Erreur "Aucun certificat homologue" dans Android 2.3 mais PAS dans 4

1
alumat

Je ne connais pas les spécificités d'Android pour les certificats SSL, mais il serait logique qu'Android n'accepte pas un certificat SSL auto-signé immédiatement. J'ai trouvé ce message sur des forums Android qui semble aborder le même problème: http://androidforums.com/Android-applications/950-imap-self-signed-ssl-certificates.html

1
Matti Lyra

Pour une raison quelconque, la solution mentionnée ci-dessus pour httpClient ne fonctionnait pas pour moi. À la fin, j'ai pu le faire fonctionner en redéfinissant correctement la méthode lors de l'implémentation de la classe personnalisée SSLSocketFactory.

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

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

Voilà comment cela a fonctionné parfaitement pour moi. Vous pouvez voir la classe personnalisée complète et son implémentation sur le fil suivant: http://blog.syedgakbar.com/2012/07/21/Android-https-and-not-trusted-server-certificate-error/

0
Syed Ghulam Akbar

Les sources qui m'ont aidé à travailler avec mon certificat auto-signé sur mon serveur AWS Apache et à me connecter avec HttpsURLConnection à partir d'un périphérique Android:

SSL sur une instance aws - Tutoriel Amazon sur SSL
Sécurité Android avec HTTPS et SSL - créer votre propre gestionnaire de confiance sur le client pour accepter votre certificat
Créer un certificat auto-signé - Script facile pour créer vos certificats

Puis j'ai fait ce qui suit:

  1. Assurez-vous que le serveur prend en charge le protocole https (cliquez ici pour installer -y mod24_ssl)
  2. Placez ce script dans un fichier create_my_certs.sh:
#!/bin/bash
FQDN=$1

# make directories to work from
mkdir -p server/ client/ all/

# Create your very own Root Certificate Authority
openssl genrsa \
  -out all/my-private-root-ca.privkey.pem \
  2048

# Self-sign your Root Certificate Authority
# Since this is private, the details can be as bogus as you like
openssl req \
  -x509 \
  -new \
  -nodes \
  -key all/my-private-root-ca.privkey.pem \
  -days 1024 \
  -out all/my-private-root-ca.cert.pem \
  -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com"

# Create a Device Certificate for each domain,
# such as example.com, *.example.com, awesome.example.com
# NOTE: You MUST match CN to the domain name or ip address you want to use
openssl genrsa \
  -out all/privkey.pem \
  2048

# Create a request from your Device, which your Root CA will sign
openssl req -new \
  -key all/privkey.pem \
  -out all/csr.pem \
  -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}"

# Sign the request from Device with your Root CA
openssl x509 \
  -req -in all/csr.pem \
  -CA all/my-private-root-ca.cert.pem \
  -CAkey all/my-private-root-ca.privkey.pem \
  -CAcreateserial \
  -out all/cert.pem \
  -days 500

# Put things in their proper place
rsync -a all/{privkey,cert}.pem server/
cat all/cert.pem > server/fullchain.pem         # we have no intermediates in this case
rsync -a all/my-private-root-ca.cert.pem server/
rsync -a all/my-private-root-ca.cert.pem client/
  1. Exécuter bash create_my_certs.sh yourdomain.com
  2. Placez les certificats à leur place sur le serveur (vous pouvez trouver la configuration dans /etc/httpd/conf.d/ssl.conf). Tous ces éléments doivent être définis:
    SSLCertificateFile
    SSLCertificateKeyFile
    SSLCertificateChainFile
    SSLCACertificateFile

  3. Redémarrez httpd en utilisant Sudo service httpd restart et assurez-vous que httpd a démarré:
    Arrêt de httpd: [OK]
    Démarrer httpd: [OK]

  4. Copiez my-private-root-ca.cert dans le dossier des ressources de votre projet Android.

  5. Créez votre gestionnaire de confiance:

    SSLContext SSLContext;

    CertificateFactory cf = CertificateFactory.getInstance ("X.509"); InputStream caInput = context.getAssets (). Open ("my-private-root-ca.cert.pem"); Certificat ca; essayez { ca = cf.generateCertificate (caInput); } enfin { caInput.close (); }

      // 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 = SSLContext.getInstance("TLS");
      SSSLContext.init(null, tmf.getTrustManagers(), null);
    
  6. Et établissez la connexion à l'aide de HttpsURLConnection:

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection (); Connection.setSSLSocketFactory (SSLContext.getSocketFactory ());

  7. Voilà, essayez votre connexion https.

0
MikeL

Je fais cette classe et trouve

package com.example.fakessl;

import Java.security.KeyManagementException;
import Java.security.NoSuchAlgorithmException;
import Java.security.SecureRandom;
import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;

import Android.util.Log;

public class CertificadoAceptar {
    private static TrustManager[] trustManagers;

    public static class _FakeX509TrustManager implements
            javax.net.ssl.X509TrustManager {
        private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};

        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        public boolean isClientTrusted(X509Certificate[] chain) {
            return (true);
        }

        public boolean isServerTrusted(X509Certificate[] chain) {
            return (true);
        }

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

    public static void allowAllSSL() {

        javax.net.ssl.HttpsURLConnection
                .setDefaultHostnameVerifier(new HostnameVerifier() {
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });

        javax.net.ssl.SSLContext context = null;

        if (trustManagers == null) {
            trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
        }

        try {
            context = javax.net.ssl.SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            Log.e("allowAllSSL", e.toString());
        } catch (KeyManagementException e) {
            Log.e("allowAllSSL", e.toString());
        }
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }
}

en code blanc ce

CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or Host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
0
Erick Guardado