it-swarm.com.de

Allen Zertifikaten vertrauen, die HttpClient über HTTPS verwenden

Kürzlich wurde eine Frage zu HttpClient über Https ( hier ) gefunden. Ich habe einige Fortschritte gemacht, bin aber auf neue Probleme gestoßen. Wie bei meinem letzten Problem kann ich nirgendwo ein Beispiel finden, das für mich funktioniert. Grundsätzlich möchte ich, dass mein Client jedes Zertifikat akzeptiert (weil ich immer nur auf einen Server zeige), aber ich bekomme immer einen javax.net.ssl.SSLException: Not trusted server certificate exception.

Also das ist was ich habe:

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

Und hier ist der Fehler, den ich bekomme:

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
369
harrisonlee

Hinweis: Implementieren Sie dies nicht in Produktionscode, den Sie jemals in einem Netzwerk verwenden werden, dem Sie nicht völlig vertrauen. Besonders alles, was über das öffentliche Internet geht. 

Ihre Frage ist genau das, was ich wissen möchte. Nachdem ich einige Suchen durchgeführt habe, lautet das Fazit:.

Auf HttpClient-Weise sollten Sie eine benutzerdefinierte Klasse aus org.Apache.http.conn.ssl.SSLSocketFactory erstellen, nicht aus org.Apache.http.conn.ssl.SSLSocketFactory selbst. Einige Hinweise finden Sie in diesem Beitrag Die benutzerdefinierte SSL-Verarbeitung funktioniert nicht mehr unter Android 2.2 FroYo .

Ein Beispiel ist wie ...

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

und verwenden Sie diese Klasse beim Erstellen der Instanz von 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();
    }
}

Übrigens, der Link unten ist für jemanden, der nach einer HttpURLConnection-Lösung sucht . Https Connection Android

Ich habe die beiden oben genannten Lösungen auf Froyo getestet, und alle funktionieren in meinen Fällen wie ein Zauber. Schließlich kann bei der Verwendung von HttpURLConnection die Umleitungsprobleme auftreten, dies steht jedoch außerhalb des Themas.

Hinweis: Bevor Sie sich dafür entscheiden, allen Zertifikaten zu vertrauen, sollten Sie die Site wahrscheinlich vollständig kennen und für den Endbenutzer nicht schädlich sein.

In der Tat sollte das Risiko, das Sie eingehen, sorgfältig geprüft werden, einschließlich der Auswirkungen der in den folgenden Kommentaren erwähnten Hacker-Mock-Site, die ich sehr schätzte. In manchen Situationen ist es zwar schwierig, sich um alle Zertifikate zu kümmern, Sie sollten jedoch die impliziten Nachteile kennen, wenn Sie allen Zertifikaten vertrauen.

406
Daniel

Grundsätzlich gibt es vier mögliche Lösungen, um eine "Nicht vertrauenswürdige" Ausnahme unter Android mit httpclient zu beheben:

  1. Vertrauen Sie allen Zertifikaten. Tun Sie das nicht, es sei denn, Sie wissen wirklich, was Sie tun.
  2. Erstellen Sie eine benutzerdefinierte SSLSocketFactory, die nur Ihrem Zertifikat vertraut. Dies funktioniert, solange Sie genau wissen, zu welchen Servern Sie eine Verbindung herstellen möchten. Sobald Sie jedoch eine Verbindung zu einem neuen Server mit einem anderen SSL-Zertifikat herstellen müssen, müssen Sie Ihre App aktualisieren.
  3. Erstellen Sie eine Keystore-Datei, die die "Master-Liste" von Android-Zertifikaten enthält, und fügen Sie dann Ihre eigene hinzu. Wenn eines dieser Zertifikate abläuft, sind Sie für die Aktualisierung in Ihrer App verantwortlich. Ich kann mir keinen Grund dafür vorstellen.
  4. Erstellen Sie eine benutzerdefinierte SSLSocketFactory, die das integrierte Zertifikat KeyStore verwendet, jedoch auf einen alternativen KeyStore für alles zurückgreift, das nicht mit dem Standardwert überprüft werden kann.

Diese Antwort verwendet Lösung Nr. 4, die mir am robustesten erscheint.

Die Lösung besteht darin, eine SSLSocketFactory zu verwenden, die mehrere KeyStores akzeptieren kann, sodass Sie Ihren eigenen KeyStore mit Ihren eigenen Zertifikaten versehen können. Auf diese Weise können Sie zusätzliche Top-Level-Zertifikate wie Thawte laden, die auf einigen Android-Geräten möglicherweise fehlen. Sie können auch Ihre eigenen selbstsignierten Zertifikate laden. Es verwendet zuerst die integrierten Standard-Gerätezertifikate und greift nur bei Bedarf auf Ihre zusätzlichen Zertifikate zurück.

Zunächst möchten Sie feststellen, welches Zertifikat in Ihrem KeyStore fehlt. Führen Sie den folgenden Befehl aus:

openssl s_client -connect www.yourserver.com:443

Und Sie werden folgende Ausgabe sehen:

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

Wie Sie sehen, stammt unser Stammzertifikat von Thawte. Gehen Sie zur Website Ihres Providers und finden Sie das entsprechende Zertifikat. Für uns war es hier , und Sie können sehen, dass das, was wir brauchten, das Copyright 2006 war.

Wenn Sie ein selbstsigniertes Zertifikat verwenden, mussten Sie den vorherigen Schritt nicht ausführen, da Sie bereits über ein Signaturzertifikat verfügen. 

Erstellen Sie dann eine Schlüsselspeicherdatei, die das fehlende Signaturzertifikat enthält. Crazybob hat Details, wie man dies auf Android macht , aber es geht darum, folgendes zu tun:

Wenn Sie es noch nicht haben, laden Sie die Bibliothek für die Hüpfburg-Anbieter herunter: http://www.bouncycastle.org/latest_releases.html . Dies wird auf Ihrem Klassenpfad weiter unten gehen.

Führen Sie einen Befehl aus, um das Zertifikat vom Server zu extrahieren und eine Pem-Datei zu erstellen. In diesem Fall mycert.pem.

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

Führen Sie dann die folgenden Befehle aus, um den Keystore zu erstellen.

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

Sie werden feststellen, dass das obige Skript das Ergebnis in res/raw/mystore.bks platziert. Jetzt haben Sie eine Datei, die Sie in Ihre Android-App laden und die fehlenden Zertifikate bereitstellen. 

Registrieren Sie dazu Ihre SSLSocketFactory für das SSL-Schema:

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

So erstellen Sie Ihre 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);
    }
}

Und schließlich der AdditionalKeyStoresSSLSocketFactory-Code, der Ihren neuen KeyStore akzeptiert und prüft, ob der integrierte KeyStore ein SSL-Zertifikat nicht überprüft:

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

}
471
emmby

Fügen Sie diesen Code vor der HttpsURLConnection hinzu und es wird fertig Ich habe es verstanden.

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

Ich hoffe das hilft dir.

65
Alok Gupta

Das ist eine schlechte Idee. Das Vertrauen eines Zertifikats ist nur (sehr) etwas besser als die Verwendung von überhaupt keinem SSL. Wenn Sie sagen "Ich möchte, dass mein Client alle Zertifikate akzeptiert (weil ich immer nur auf einen Server zeige)", gehen Sie davon aus, dass das Zeigen auf "einen Server" in gewisser Weise sicher ist. 

Sie sind völlig offen für einen Man-in-the-Middle-Angriff, wenn Sie einem Zertifikat vertrauen. Jeder kann Ihre Verbindung vertreten, indem Sie eine separate SSL-Verbindung mit Ihnen und dem End-Server aufbauen. Das MITM hat dann Zugriff auf Ihre gesamte Anfrage und Antwort. Wenn Sie nicht wirklich SSL wirklich nicht benötigen (Ihre Nachricht ist nicht sensibel und führt keine Authentifizierung durch), sollten Sie allen Zertifikaten nicht blind vertrauen. 

Sie sollten das öffentliche Zertifikat mithilfe von keytool zu einem Jks hinzufügen und dieses dann zum Erstellen Ihrer Socket-Factory verwenden.

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

Dies hat einen Vorbehalt zu beachten. Das Zertifikat läuft irgendwann ab und der Code funktioniert zu diesem Zeitpunkt nicht mehr. Sie können leicht feststellen, wann dies geschieht, indem Sie das Zertifikat betrachten.

32
Dan

Sie können die HttpURLConnection-SSL-Prüfung zu Testzwecken auf diese Weise seit API 8 deaktivieren

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    if (conn instanceof HttpsURLConnection) {
        HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
        httpsConn.setSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null));
        httpsConn.setHostnameVerifier(new AllowAllHostnameVerifier());
    }
17
hfmanson

Die API von HttpComponents wurde geändert. Es funktioniert mit dem folgenden Code.

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

Der obige Code in https://stackoverflow.com/a/6378872/1553004 ist korrekt, es sei denn, er MUSS auch den Hostnamen-Verifizierer aufrufen:

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

Ich habe mich ausdrücklich bei stackoverflow angemeldet, um diesen Fix hinzuzufügen. Beachte meine Warnung!

10
Robert Blair

Ich füge eine Antwort für diejenigen hinzu, die den httpclient-4.5 verwenden, und funktioniert wahrscheinlich auch für 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);
    }
}
}
5
raisercostin

Es war für mich keine echte Alternative, allen Zertifikaten zu vertrauen. Daher habe ich Folgendes getan, damit HttpsURLConnection einem neuen Zertifikat vertraut (siehe auch http://nelenkov.blogspot.jp/2011/12/ using-custom-certificate-trust- store-on.html ).

  1. Holen Sie sich das Zertifikat. Dies wurde durch Exportieren des Zertifikats in Firefox erledigt (klicken Sie auf das kleine Schlosssymbol, rufen Sie die Zertifikatdetails ab, klicken Sie auf Exportieren), und verwenden Sie dann portecle , um einen Truststore (BKS) zu exportieren.

  2. Laden Sie den Truststore aus /res/raw/geotrust_cert.bks mit dem folgenden Code:

        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());
    
4
koljaTM

Ich habe dies verwendet und es funktioniert für mich auf allen Betriebssystemen.

/**
 * 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();
    }
}
3
Baiju Sharma

Ich habe mir die Antwort von "emmby" angesehen (geantwortet am 16. Juni 11 um 21:29 Uhr), Punkt 4: "Erstellen Sie eine benutzerdefinierte SSLSocketFactory, die das integrierte Zertifikat KeyStore verwendet, jedoch auf einen alternativen KeyStore für alles zurückgreift, was fehlschlägt mit dem Standard überprüfen. "

Dies ist eine vereinfachte Implementierung. Laden Sie den Systemschlüsselspeicher und fügen Sie ihn mit dem Anwendungsschlüsselspeicher zusammen.

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

Ein einfacher Modus zum Konvertieren von JKS in 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

* Hinweis: In Android 4.0 (ICS) hat sich der Trust Store geändert. Weitere Informationen: http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html

3
ggrandes

Hier ist eine sehr einfache Version, die 4.1.2-httpclient-Code verwendet. Dieser kann dann an jeden beliebigen Trust-Algorithmus angepasst werden.

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

Für diejenigen, die zulassen möchten, dass alle Zertifikate (zu Testzwecken) über OAuth funktionieren, gehen Sie folgendermaßen vor:

1) Laden Sie den Quellcode der Android OAuth API hier herunter: https://github.com/kaeppler/signpost

2) Suchen Sie die Datei "CommonsHttpOAuthProvider"

3) Ändern Sie es wie folgt:

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

Die obige "MySSLSocketFactory" basiert auf der akzeptierten Antwort. Um es noch einfacher zu machen, hier die komplette Klasse:

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

}

Hoffe das hilft jemandem.

3
Tiago

Alle Personen, die noch mit StartCom-SSL-Zertifikaten unter Android 2.1 zu kämpfen haben, besuchen https://www.startssl.com/certs/ und laden das ca.pem herunter, das sich jetzt in der answer von @emmby ersetzen 

`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`

mit 

 `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`

Sollte aus dem Kasten heraus arbeiten. Ich hatte mehr als einen Tag lang Probleme damit, selbst nach einer perfekten Antwort von @emmby .. Hoffe das hilft jemandem ...

0
13hsoj

Bildbeschreibung hier eingeben

Ein sspi ist in xamarin Android fehlgeschlagen.

Ich habe diese Lösung gefunden; Fügen Sie diesen Code ein, bevor Sie auf einen HTTPS-Link klicken

const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;
0
vinothswami

verwenden Sie diese Klasse

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

}

0
Ali Bagheri

Fügen Sie einfach -Dtrust_all_cert=true zu VM Argumenten hinzu. Dieses Argument weist Java an, Zertifikatprüfungen zu ignorieren.

0
Ayman Hussain