Approuver tous les certificats en utilisant HttpClient sur HTTPS

393

Récemment posté une question concernant les HttpClientover Https ( trouvée ici ). J'ai fait des progrès, mais j'ai rencontré de nouveaux problèmes. Comme pour mon dernier problème, je n'arrive pas à trouver d'exemple n'importe où qui fonctionne pour moi. Fondamentalement, je veux que mon client accepte n'importe quel certificat (parce que je ne pointe que vers un serveur) mais je reçois toujours unjavax.net.ssl.SSLException: Not trusted server certificate exception.

Voici donc ce que j'ai:


    public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS {

        HttpPost post = new HttpPost(new URI(PROD_URL));
        post.setEntity(new StringEntity(BODY));

        KeyStore trusted = KeyStore.getInstance("BKS");
        trusted.load(null, "".toCharArray());
        SSLSocketFactory sslf = new SSLSocketFactory(trusted);
        sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme ("https", sslf, 443));
        SingleClientConnManager cm = new SingleClientConnManager(post.getParams(),
                schemeRegistry);

        HttpClient client = new DefaultHttpClient(cm, post.getParams());
        HttpResponse result = client.execute(post);
    }

Et voici l'erreur que je reçois:

    W/System.err(  901): javax.net.ssl.SSLException: Not trusted server certificate 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360) 
    W/System.err(  901):    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321) 
    W/System.err(  901):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
    W/System.err(  901):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49) 
    W/System.err(  901): Caused by: java.security.cert.CertificateException: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355) 
    W/System.err(  901):    ... 12 more 
    W/System.err(  901): Caused by: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645) 
    W/System.err(  901):    at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.<init>(TrustManagerImpl.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134) 
    W/System.err(  901):    at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err(  901):     at org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:190) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:216) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107) 
    W/System.err(  901):    ... 2 more
Harrisonlee
la source
17
J'avais besoin de le faire pour un usage interne. J'espère vraiment que vous ne permettez pas aux utilisateurs extérieurs à votre entreprise d'utiliser votre application, car vous l'avez ouverte à l'homme dans l'attaque du milieu et ils seraient alors vulnérables à une personne détournant leur session. Néanmoins, je dois le faire temporairement pour certains tests jusqu'à ce que j'obtienne le vrai certificat en main ... j'espère que vous le faites pour le même type de raison temporaire ou que l'application n'est utilisée qu'en interne.
Dean Hiller
J'ai essayé ces solutions sur le client http apache 4.3, mais elles sont pour la plupart obsolètes. Voici une solution non obsolète: stackoverflow.com/a/18941950/2039471
Alexander Chzhen
Java 1.6 ne prend pas en charge SNI, ce qui est également problématique dans ces scénarios - si vous ne construisez pas la demande correctement, vous pourriez obtenir un certificat qui ne correspond pas à la demande. Voir issues.apache.org/jira/browse/HTTPCLIENT-1119
Bron Davies
2
Cette question est citée dans l'article du Code le plus dangereux du monde comme exemple de raisonnement fallacieux. (document de recherche: cs.utexas.edu/~shmat/shmat_ccs12.pdf )
mk_

Réponses:

421

Remarque: N'implémentez pas cela dans le code de production que vous allez utiliser sur un réseau auquel vous ne faites pas entièrement confiance. Surtout tout ce qui se passe sur Internet public.

Votre question est exactement ce que je veux savoir. Après avoir fait quelques recherches, la conclusion est la suivante.

De la manière HttpClient, vous devez créer une classe personnalisée à partir de org.apache.http.conn.ssl.SSLSocketFactory, et non celle org.apache.http.conn.ssl.SSLSocketFactory elle-même. Certains indices peuvent être trouvés dans cet article La gestion SSL personnalisée a cessé de fonctionner sur Android 2.2 FroYo .

Un exemple est comme ...

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;

import org.apache.http.conn.ssl.SSLSocketFactory;
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();
    }
}

et utilisez cette classe lors de la création d'une instance de HttpClient.

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

        MySSLSocketFactory 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();
    }
}

BTW, le lien ci-dessous est pour quelqu'un qui recherche une solution HttpURLConnection. Connexion Https Android

J'ai testé les deux types de solutions ci-dessus sur froyo, et ils fonctionnent tous comme un charme dans mes cas. Enfin, l'utilisation de HttpURLConnection peut être confrontée aux problèmes de redirection, mais cela dépasse le sujet.

Remarque: Avant de décider de faire confiance à tous les certificats, vous devez probablement bien connaître le site et ne pas le nuire à l'utilisateur final.

En effet, le risque que vous prenez doit être soigneusement pris en compte, y compris l'effet du site simulé du pirate mentionné dans les commentaires suivants que j'ai profondément apprécié. Dans certaines situations, même s'il peut être difficile de s'occuper de tous les certificats, vous feriez mieux de connaître les inconvénients implicites de leur faire confiance.

Daniel
la source
150
cette réponse devrait probablement noter que faire confiance à tous les certificats est horriblement peu sûr et annule tout le but de ssl ...
yanokwa
22
@sweeney - Sauf qu'il n'est pas garanti que vous parlez au serveur que vous pensez être. Si quelqu'un a détruit un serveur DNS, vous pourriez communiquer une clé de cryptage avec le serveur d'un pirate.
Richard Szalay
12
@sweeney En d'autres termes, vous êtes désormais exposé aux attaques de l'homme du milieu. Vous devez également noter que ce code ne répond pas aux spécifications: vérifiez le Javadoc. getAcceptedIssuers()n'est pas autorisé à retourner null.
Marquis de Lorne
25
-1 Parce que c'est une terrible idée d'accepter tous les certificats. Il est dommage qu'il y ait autant de blogs et de tutoriels qui guident avec plaisir les développeurs Java sur la voie de la mauvaise chose.
Tim Bender
57
+1 Parce que j'avais besoin d'une solution rapide à des fins de débogage uniquement. Je ne l'utiliserais pas en production en raison des problèmes de sécurité que d'autres ont mentionnés, mais c'était exactement ce dont j'avais besoin pour les tests. Je vous remercie!
Danation
495

Vous disposez essentiellement de quatre solutions potentielles pour corriger une exception "Non approuvé" sur Android en utilisant httpclient:

  1. Faites confiance à tous les certificats. Ne faites pas cela, sauf si vous savez vraiment ce que vous faites.
  2. Créez un SSLSocketFactory personnalisé qui ne fait confiance qu'à votre certificat. Cela fonctionne tant que vous savez exactement à quels serveurs vous allez vous connecter, mais dès que vous devez vous connecter à un nouveau serveur avec un certificat SSL différent, vous devrez mettre à jour votre application.
  3. Créez un fichier de clés contenant la "liste principale" d'Android, puis ajoutez le vôtre. Si l'un de ces certificats expire en cours de route, vous êtes responsable de leur mise à jour dans votre application. Je ne vois aucune raison de faire ça.
  4. Créez un SSLSocketFactory personnalisé qui utilise le certificat KeyStore intégré, mais retombe sur un autre KeyStore pour tout ce qui ne parvient pas à vérifier avec la valeur par défaut.

Cette réponse utilise la solution # 4, qui me semble la plus robuste.

La solution consiste à utiliser un SSLSocketFactory qui peut accepter plusieurs KeyStores, vous permettant de fournir votre propre KeyStore avec vos propres certificats. Cela vous permet de charger des certificats de niveau supérieur supplémentaires tels que Thawte qui pourraient être manquants sur certains appareils Android. Il vous permet également de charger vos propres certificats auto-signés. Il utilisera d'abord les certificats de périphérique par défaut intégrés et ne recourra à vos certificats supplémentaires que si nécessaire.

Tout d'abord, vous voudrez déterminer quel certificat vous manque dans votre KeyStore. Exécutez la commande suivante:

openssl s_client -connect www.yourserver.com:443

Et vous verrez une sortie comme celle-ci:

Certificate chain
 0 s:/O=www.yourserver.com/OU=Go to 
   https://www.thawte.com/repository/index.html/OU=Thawte SSL123 
   certificate/OU=Domain Validated/CN=www.yourserver.com
   i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
 1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 
   2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA

Comme vous pouvez le voir, notre certificat racine provient de Thawte. Accédez au site Web de votre fournisseur et recherchez le certificat correspondant. Pour nous, c'était ici , et vous pouvez voir que celui dont nous avions besoin était celui de Copyright 2006.

Si vous utilisez un certificat auto-signé, vous n'avez pas eu besoin de faire l'étape précédente car vous avez déjà votre certificat de signature.

Créez ensuite un fichier de clés contenant le certificat de signature manquant. Crazybob a des détails sur la façon de le faire sur Android , mais l'idée est de faire ce qui suit:

Si vous ne l'avez pas déjà, téléchargez la bibliothèque du fournisseur de château gonflable à partir de: http://www.bouncycastle.org/latest_releases.html . Cela ira sur votre chemin de classe ci-dessous.

Exécutez une commande pour extraire le certificat du serveur et créer un fichier pem. Dans ce cas, mycert.pem.

echo | openssl s_client -connect ${MY_SERVER}:443 2>&1 | \
 sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem

Exécutez ensuite les commandes suivantes pour créer le fichier de clés.

export CLASSPATH=/path/to/bouncycastle/bcprov-jdk15on-155.jar
CERTSTORE=res/raw/mystore.bks
if [ -a $CERTSTORE ]; then
    rm $CERTSTORE || exit 1
fi
keytool \
      -import \
      -v \
      -trustcacerts \
      -alias 0 \
      -file <(openssl x509 -in mycert.pem) \
      -keystore $CERTSTORE \
      -storetype BKS \
      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
      -providerpath /path/to/bouncycastle/bcprov-jdk15on-155.jar \
      -storepass some-password

Vous remarquerez que le script ci-dessus place le résultat res/raw/mystore.bks. Vous avez maintenant un fichier que vous allez charger dans votre application Android qui fournit le ou les certificats manquants.

Pour ce faire, enregistrez votre SSLSocketFactory pour le schéma SSL:

final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", createAdditionalCertsSSLSocketFactory(), 443));

// and then however you create your connection manager, I use ThreadSafeClientConnManager
final HttpParams params = new BasicHttpParams();
...
final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params,schemeRegistry);

Pour créer votre SSLSocketFactory:

protected org.apache.http.conn.ssl.SSLSocketFactory createAdditionalCertsSSLSocketFactory() {
    try {
        final KeyStore ks = KeyStore.getInstance("BKS");

        // the bks file we generated above
        final InputStream in = context.getResources().openRawResource( R.raw.mystore);  
        try {
            // don't forget to put the password used above in strings.xml/mystore_password
            ks.load(in, context.getString( R.string.mystore_password ).toCharArray());
        } finally {
            in.close();
        }

        return new AdditionalKeyStoresSSLSocketFactory(ks);

    } catch( Exception e ) {
        throw new RuntimeException(e);
    }
}

Et enfin, le code AdditionalKeyStoresSSLSocketFactory, qui accepte votre nouveau KeyStore et vérifie si le KeyStore intégré ne parvient pas à valider un certificat SSL:

/**
 * Allows you to trust certificates from additional KeyStores in addition to
 * the default KeyStore
 */
public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory {
    protected SSLContext sslContext = SSLContext.getInstance("TLS");

    public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(null, null, null, null, null, null);
        sslContext.init(null, new TrustManager[]{new AdditionalKeyStoresTrustManager(keyStore)}, null);
    }

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

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



    /**
     * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
     */
    public static class AdditionalKeyStoresTrustManager implements X509TrustManager {

        protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();


        protected AdditionalKeyStoresTrustManager(KeyStore... additionalkeyStores) {
            final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();

            try {
                // The default Trustmanager with default keystore
                final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                original.init((KeyStore) null);
                factories.add(original);

                for( KeyStore keyStore : additionalkeyStores ) {
                    final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    additionalCerts.init(keyStore);
                    factories.add(additionalCerts);
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }



            /*
             * Iterate over the returned trustmanagers, and hold on
             * to any that are X509TrustManagers
             */
            for (TrustManagerFactory tmf : factories)
                for( TrustManager tm : tmf.getTrustManagers() )
                    if (tm instanceof X509TrustManager)
                        x509TrustManagers.add( (X509TrustManager)tm );


            if( x509TrustManagers.size()==0 )
                throw new RuntimeException("Couldn't find any X509TrustManagers");

        }

        /*
         * Delegate to the default trust manager.
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0);
            defaultX509TrustManager.checkClientTrusted(chain, authType);
        }

        /*
         * Loop over the trustmanagers until we find one that accepts our server
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            for( X509TrustManager tm : x509TrustManagers ) {
                try {
                    tm.checkServerTrusted(chain,authType);
                    return;
                } catch( CertificateException e ) {
                    // ignore
                }
            }
            throw new CertificateException();
        }

        public X509Certificate[] getAcceptedIssuers() {
            final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
            for( X509TrustManager tm : x509TrustManagers )
                list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
            return list.toArray(new X509Certificate[list.size()]);
        }
    }

}
emmby
la source
Hé @ emmby, cela semble être la réponse parfaite à mon problème, mais je n'ai toujours pas de connexion SSL. Pouvez-vous, s'il vous plaît, y jeter un œil? http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
Matthias B
Merci pour l'excellent résumé @emmby! Je reçois parfois un délai très long, puis une javax.net.ssl.SSLException: erreur de lecture :. Une idée? Comment puis-je définir un délai d'expiration si la solution est identique à stackoverflow.com/questions/5909308/android-2-3-4-ssl-problem ?
Edwin Evans
3
@emmby, pourriez-vous dire où dois-je mettre ce code export CLASSPATH = bcprov-jdk16-145.jar CERTSTORE = res / raw / mystore.bks if [-a $ CERTSTORE]; puis rm $ CERTSTORE || exit 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -in mycert.pem) \ -keystore $ CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider. BouncyCastleProvider \ -providerpath /usr/share/java/bcprov.jar \ -storepass some-password
Rikki Tikki Tavi
1
Salut @ emmby. J'utilise votre solution dans mon application et j'utilise un certificat auto-signé de mon serveur mais j'obtiens un j'utilise certificat j'obtiens CertificateException () dans la méthode checkServerTrusted () . J'ai essayé de commenter cette exception de lancement, et cela fonctionne. s'il ne valide pas mon certificat de serveur, puis-je le gérer d'une autre manière, pouvez-vous s'il vous plaît guider quelle est la meilleure solution dans ce cas?
Ankit
7
Cela devrait être marqué comme la bonne réponse. L'une des réponses les plus complètes et les mieux écrites que j'ai jamais vues sur SO. Dope
Kachi
74

Ajoutez ce code avant le HttpsURLConnectionet ce sera fait. J? ai compris.

private void trustEveryone() { 
    try { 
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
                    public boolean verify(String hostname, SSLSession session) { 
                            return true; 
                    }}); 
            SSLContext context = SSLContext.getInstance("TLS"); 
            context.init(null, new X509TrustManager[]{new X509TrustManager(){ 
                    public void checkClientTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public void checkServerTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public X509Certificate[] getAcceptedIssuers() { 
                            return new X509Certificate[0]; 
                    }}}, new SecureRandom()); 
            HttpsURLConnection.setDefaultSSLSocketFactory( 
                            context.getSocketFactory()); 
    } catch (Exception e) { // should never happen 
            e.printStackTrace(); 
    } 
} 

J'espère que ceci vous aide.

Alok Gupta
la source
22
Voir les remarques ci-dessus sous la réponse acceptée. Cette «solution» est radicalement précaire.
Marquis de Lorne
5
C'est la solution Q&D idéale. Court et "ça marche".
Steve Smith
5
Réponse parfaite à des fins de test !!! Et oui, c'est une mauvaise idée à utiliser en production, mais allez ... cela devrait être clair pour tous ceux qui regardent le titre de la question. Il y répond toujours mieux / plus court / avec le même (in) niveau de sécurité!
Lévite
34

C'est une mauvaise idée. Faire confiance à un certificat n'est que (très) légèrement meilleur que de ne pas utiliser de SSL du tout. Lorsque vous dites «Je veux que mon client accepte n'importe quel certificat (parce que je ne pointe que vers un serveur)», vous supposez que cela signifie que pointer vers «un serveur» est sûr, ce qui n'est pas sur un réseau public.

Vous êtes complètement ouvert à une attaque d'homme au milieu en faisant confiance à n'importe quel certificat. Tout le monde peut proxy votre connexion en établissant une connexion SSL distincte avec vous et avec le serveur final. Le MITM a alors accès à l'ensemble de votre demande et réponse. À moins que vous n'ayez pas vraiment besoin de SSL en premier lieu (votre message n'a rien de sensible et ne fait pas d'authentification), vous ne devez pas faire confiance à tous les certificats à l'aveuglette.

Vous devriez envisager d'ajouter le certificat public à un jks à l'aide de keytool et de l'utiliser pour créer votre fabrique de socket, comme ceci:

    KeyStore ks = KeyStore.getInstance("JKS");

    // get user password and file input stream
    char[] password = ("mykspassword")).toCharArray();
    ClassLoader cl = this.getClass().getClassLoader();
    InputStream stream = cl.getResourceAsStream("myjks.jks");
    ks.load(stream, password);
    stream.close();

    SSLContext sc = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

    kmf.init(ks, password);
    tmf.init(ks);

    sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);

    return sc.getSocketFactory();

Cela a une mise en garde à surveiller. Le certificat expirera finalement et le code cessera de fonctionner à ce moment-là. Vous pouvez facilement déterminer quand cela se produira en consultant le certificat.

Dan
la source
5
Si vous n'utilisez pas l'authentification par certificat client, du côté client, vous n'avez pas besoin d'un gestionnaire de clés (à utiliser nulldans SSLContext.init). You should also use the default algorithms (KMF/TMF.getDefaultAlgorithm() ), instead of hard-coding SunX509` (d'autant plus que la valeur par défaut pour TMF est en fait PKIXsur la JVM Sun / Oracle).
Bruno
Existe un fichier de certificats racine prêt à l'emploi? (comme le font les navigateurs)
dani herrera
D'où myjks.jksvient-il?
zionpi
1
@zionpi Généré à l'aide de Java "keytool".
Dan
22

Vous pouvez désactiver la vérification SSL HttpURLConnection à des fins de test de cette façon depuis l'API 8:

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    if (conn instanceof HttpsURLConnection) {
        HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
        httpsConn.setSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null));
        httpsConn.setHostnameVerifier(new AllowAllHostnameVerifier());
    }
hfmanson
la source
2
org.apache.http.conn.ssl.AllowAllHostnameVerifierest obsolète.
zackygaurav
2
@zackygaurav Selon le javadoc , AllowAllHostnameVerifierest remplacé par NoopHostnameVerifier"
DLight
10

L'API de HttpComponents a été modifiée. Cela fonctionne avec le code ci-dessous.

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        }, new AllowAllHostnameVerifier());

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https",8444, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        e.printStackTrace();
        return new DefaultHttpClient();
    }
}
Prabhu Periasamy
la source
L'utilisation d'une stratégie de confiance personnalisée est la bonne réponse. Merci.
Matt Friedman
10

Le code ci-dessus dans https://stackoverflow.com/a/6378872/1553004 est correct, sauf qu'il DOIT également appeler le vérificateur de nom d'hôte:

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

Je me suis inscrit à stackoverflow expressément pour ajouter ce correctif. Tenez compte de mon avertissement!

Robert Blair
la source
Une fois que vous avez vérifié le certificat de cette façon lors de la première connexion, que faites-vous avec les connexions suivantes? Tirez-vous parti des connaissances acquises lors de la première connexion? Que faire si un faux certificat du même nom est utilisé lors de la tentative de connexion 3?
jww
6

J'ajoute une réponse pour ceux qui utilisent httpclient-4.5, et fonctionne probablement aussi pour 4.4.

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.fluent.ContentResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;



public class HttpClientUtils{

public static HttpClient getHttpClientWithoutSslValidation_UsingHttpClient_4_5_2() {
    try {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); 
        return httpclient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}
raisercostine
la source
qu'est-ce que la nouvelle classe NoopHostnameVerifier ()?
Mushtakim Ahmed Ansari
1
@MushtakimAhmedAnsari D'après la documentation: "NO_OP HostnameVerifier désactive essentiellement la vérification du nom d'hôte. Cette implémentation est une opération sans objet et ne lève jamais l'exception SSLE."
raisercostin
Merci pour la bonne réponse. Celui-ci devrait obtenir plus de votes.
Abhay Dwivedi
Comment est-ce que je l'utilise? ou suggérez-vous que le simple fait d'avoir la classe remplacera les vérifications des certificats SSL?
behelit
Oui. que httpClient lorsqu'il est utilisé ne validera pas les certificats https
raisercostin
4

Faire confiance à tous les certificats n'était pas une véritable alternative pour moi, j'ai donc fait ce qui suit pour que HttpsURLConnection approuve un nouveau certificat (voir aussi http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store- on.html ).

  1. Obtenez le certificat; Je l'ai fait en exportant le certificat dans Firefox (cliquez sur la petite icône de verrouillage, obtenez les détails du certificat, cliquez sur exporter), puis j'ai utilisé portecle pour exporter un fichier de clés certifiées (BKS).

  2. Chargez le Truststore depuis /res/raw/geotrust_cert.bks avec le code suivant:

        final KeyStore trustStore = KeyStore.getInstance("BKS");
        final InputStream in = context.getResources().openRawResource(
                R.raw.geotrust_cert);
        trustStore.load(in, null);
    
        final TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
    
        final SSLContext sslCtx = SSLContext.getInstance("TLS");
        sslCtx.init(null, tmf.getTrustManagers(),
                new java.security.SecureRandom());
    
        HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx
                .getSocketFactory());
koljaTM
la source
Je reçois cette erreur. IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate. Cela lors de l'exécution de l'appel d'exécution réel sur le HttpClient après la configuration ci-dessus.
Michael
3

Voici une version très simple utilisant le code httpclient 4.1.2. Cela peut ensuite être modifié pour n'importe quel algorithme de confiance que vous jugez bon.

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        });
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https", 443, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}
Joseph Valerio
la source
3

Je suis regardé la réponse de "emmby" (répondu le 16 juin 11 à 21:29), élément # 4: "Créer un SSLSocketFactory personnalisé qui utilise le certificat KeyStore intégré, mais retombe sur un autre KeyStore pour tout ce qui échoue pour vérifier avec la valeur par défaut. "

Il s'agit d'une implémentation simplifiée. Chargez le fichier de clés système et fusionnez avec le fichier de clés de l'application.

public HttpClient getNewHttpClient() {
    try {
        InputStream in = null;
        // Load default system keystore
        KeyStore trusted = KeyStore.getInstance(KeyStore.getDefaultType()); 
        try {
            in = new BufferedInputStream(new FileInputStream(System.getProperty("javax.net.ssl.trustStore"))); // Normally: "/system/etc/security/cacerts.bks"
            trusted.load(in, null); // no password is "changeit"
        } finally {
            if (in != null) {
                in.close();
                in = null;
            }
        }

        // Load application keystore & merge with system
        try {
            KeyStore appTrusted = KeyStore.getInstance("BKS"); 
            in = context.getResources().openRawResource(R.raw.mykeystore);
            appTrusted.load(in, null); // no password is "changeit"
            for (Enumeration<String> e = appTrusted.aliases(); e.hasMoreElements();) {
                final String alias = e.nextElement();
                final KeyStore.Entry entry = appTrusted.getEntry(alias, null);
                trusted.setEntry(System.currentTimeMillis() + ":" + alias, entry, null);
            }
        } finally {
            if (in != null) {
                in.close();
                in = null;
            }
        }

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

        SSLSocketFactory sf = new SSLSocketFactory(trusted);
        sf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

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

Un mode simple pour convertir de JKS en BKS:

keytool -importkeystore -destkeystore cacerts.bks -deststoretype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-141.jar -deststorepass changeit -srcstorepass changeit -srckeystore $JAVA_HOME/jre/lib/security/cacerts -srcstoretype JKS -noprompt

* Remarque: dans Android 4.0 (ICS), le Trust Store a changé, plus d'informations: http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html

ggrandes
la source
3

Pour ceux qui souhaitent autoriser tous les certificats à fonctionner (à des fins de test) sur OAuth, procédez comme suit:

1) Téléchargez le code source de l'API Android OAuth ici: https://github.com/kaeppler/signpost

2) Trouvez le fichier "CommonsHttpOAuthProvider" classe

3) Modifiez-le comme ci-dessous:

public class CommonsHttpOAuthProvider extends AbstractOAuthProvider {

private static final long serialVersionUID = 1L;

private transient HttpClient httpClient;

public CommonsHttpOAuthProvider(String requestTokenEndpointUrl, String accessTokenEndpointUrl,
        String authorizationWebsiteUrl) {
    super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl);


    //this.httpClient = new DefaultHttpClient();//Version implemented and that throws the famous "javax.net.ssl.SSLException: Not trusted server certificate" if the certificate is not signed with a CA
    this.httpClient = MySSLSocketFactory.getNewHttpClient();//This will work with all certificates (for testing purposes only)
}

Le "MySSLSocketFactory" ci-dessus est basé sur la réponse acceptée. Pour le rendre encore plus facile, voici la classe complète:

package com.netcomps.oauth_example;

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;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
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.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

//http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https
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() {

        @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;
        }
    };

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



public static 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();
    }
}

}

J'espère que cela aide quelqu'un.

Tiago
la source
1
La question était HttpClientet HTTPS; pas OAuth pour Android à partir d'un projet GitHub.
jww
3

Je l'ai utilisé et cela fonctionne pour moi sur tous les OS.

/**
 * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
 * aid testing on a local box, not for use on production.
 */


private static void disableSSLCertificateChecking() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }
    } };

    try {
        SSLContext sc = SSLContext.getInstance("TLS");

        sc.init(null, trustAllCerts, new java.security.SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}
Baiju Sharma
la source
Bonjour @ yegor256, j'utilise ce code, mais j'ai toujours un problème de prise de contact SSL
user2028
0

Tout organisme qui éprouve encore des difficultés avec les certificats SSL StartCom sur Android 2.1, visitez https://www.startssl.com/certs/ et téléchargez le ca.pem, maintenant dans la réponse fournie par @emmby replace

`export CLASSPATH=bcprov-jdk16-145.jar
 CERTSTORE=res/raw/mystore.bks
      if [ -a $CERTSTORE ]; then
          rm $CERTSTORE || exit 1
      fi
 keytool \
  -import \
  -v \
  -trustcacerts \
  -alias 0 \
  -file <(openssl x509 -in mycert.pem) \
  -keystore $CERTSTORE \
  -storetype BKS \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath /usr/share/java/bcprov.jar \
  -storepass some-password`

avec

 `export CLASSPATH=bcprov-jdk16-145.jar
 CERTSTORE=res/raw/mystore.bks
      if [ -a $CERTSTORE ]; then
          rm $CERTSTORE || exit 1
      fi
 keytool \
  -import \
  -v \
  -trustcacerts \
  -alias 0 \
  -file <(openssl x509 -in ca.pem) \
  -keystore $CERTSTORE \
  -storetype BKS \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath /usr/share/java/bcprov.jar \
  -storepass some-password`

Devrait fonctionner hors de la boîte. J'avais du mal pendant plus d'une journée même après une réponse parfaite de @emmby .. J'espère que cela aide quelqu'un ...

13hsoj
la source
0

utiliser cette classe

public class WCFs
{
    //  https://192.168.30.8/myservice.svc?wsdl
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "192.168.30.8";
private static final String SERVICE = "/myservice.svc?wsdl";
private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";


public static Thread myMethod(Runnable rp)
{
    String METHOD_NAME = "myMethod";

    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

    request.addProperty("Message", "Https WCF Running...");
    return _call(rp,METHOD_NAME, request);
}

protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
{
    final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    int TimeOut = 5*1000;

    envelope.dotNet = true;
    envelope.bodyOut = soapReq;
    envelope.setOutputSoapObject(soapReq);

    final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);

    try
    {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
        {
            @Override
            public boolean verify(String hostname, SSLSession session)
            {
                return true;
            }
        });

        KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
        ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));


    }
    catch(Exception e){}

    HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
    {
        @Override
        public void run()
        {
            Handler h = new Handler(Looper.getMainLooper());
            Object response = null;

            for(int i=0; i<4; i++)
            {
                response = send(envelope, httpTransport_net , METHOD_NAME, null);

                try
                {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}

                if(response != null)
                    break;

                ThreadHelper.threadSleep(250);
            }

            if(response != null)
            {
                if(rp != null)
                {
                    rp.setArguments(response.toString());
                    h.post(rp);
                }
            }
            else
            {
                if(Thread.currentThread().isInterrupted())
                    return;

                if(rp != null)
                {
                    rp.setExceptionState(true);
                    h.post(rp);
                }
            }

            ThreadHelper.stopThread(this);
        }
    };

    thread.start();

    return thread;
}


private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
{
    try
    {
        if(headerList != null)
            androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
        else
            androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);

        Object res = envelope.getResponse();

        if(res instanceof SoapPrimitive)
            return (SoapPrimitive) envelope.getResponse();
        else if(res instanceof SoapObject)
            return ((SoapObject) envelope.getResponse());
    }
    catch(Exception e)
    {}

    return null;
}

public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
{
    try
    {
        InputStream inputStream = ResourceMaster.openRaw(id);
        KeyStore keystore = KeyStore.getInstance(algorithm);
        keystore.load(inputStream, filePassword.toCharArray());
        inputStream.close();

        return keystore;
    }
    catch(Exception e)
    {}

    return null;
}

public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
{
    try
    {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustKey);

        SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
        context.init(null, tmf.getTrustManagers(), null);

        return context.getSocketFactory();
    }
    catch(Exception e){}

    return null;
}

}

Ali Bagheri
la source
0

entrez la description de l'image ici

Un sspi a échoué dans xamarin android.

J'ai trouvé cette solution; mettre ce code avant de cliquer sur un lien HTTPS

const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;
vinothswami
la source
-3

travailler avec tous les https

httpClient = new DefaultHttpClient();

SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

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

ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, ssf));
cezarius
la source
2
Répète simplement la même non-solution fallacieuse et non sécurisée qui a déjà été discutée et rejetée dans ce fil.
Marquis de Lorne
-3

Il y a beaucoup de réponses ci-dessus mais je n'ai pas réussi à faire fonctionner correctement l'une d'entre elles (avec mon temps limité), donc pour toute autre personne dans la même situation, vous pouvez essayer le code ci-dessous qui fonctionnait parfaitement pour mes tests de java:

    public static HttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

            public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory ssf = new SSLSocketFactory(ctx);
        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = base.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", ssf, 443));
        return new DefaultHttpClient(ccm, base.getParams());
    } catch (Exception ex) {
        return null;
    }
}

et appeler comme:

DefaultHttpClient baseClient = new DefaultHttpClient();
HttpClient httpClient = wrapClient(baseClient );

Référence: http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/

faux
la source
Pour citer EJP: "répète simplement la même non-solution fallacieuse et non sécurisée qui a déjà été discutée et rejetée dans ce fil" .
jww
-4

Utilisez simplement ceci -

public DefaultHttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };
    ctx.init(null, new TrustManager[]{tm}, null);
    SSLSocketFactory ssf = new SSLSocketFactory(ctx);
    ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    ClientConnectionManager ccm = base.getConnectionManager();
    SchemeRegistry sr = ccm.getSchemeRegistry();
    sr.register(new Scheme("https", ssf, 443));
    return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
    return null;
}
}
Hemant
la source
Pour citer EJP: "répète simplement la même non-solution fallacieuse et non sécurisée qui a déjà été discutée et rejetée dans ce fil" .
jww
-5

La réponse de Daniel était bonne sauf que je devais changer ce code ...

    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);

à ce code ...

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
    SchemeRegistry registry = ccm.getShemeRegistry()
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    registry.register(new Scheme("https", sf, 443));

pour le faire fonctionner.

Dean Hiller
la source
5
comment cela devrait-il fonctionner? vous référencez le registre avant même de le créer!
Matthias B