Ufanie wszystkim certyfikatom przy użyciu HttpClient przez HTTPS

393

Niedawno opublikowałem pytanie dotyczące HttpClientponad Https ( znaleziono tutaj ). Poczyniłem pewne postępy, ale napotkałem nowe problemy. Podobnie jak w przypadku mojego ostatniego problemu, nigdzie nie mogę znaleźć przykładu, który by mi pasował. Zasadniczo chcę, aby mój klient zaakceptował dowolny certyfikat (ponieważ zawsze wskazuję tylko jeden serwer), ale nadal otrzymujęjavax.net.ssl.SSLException: Not trusted server certificate exception.

Oto co mam:


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

I oto pojawia się błąd:

    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
źródło
17
Musiałem to zrobić na użytek wewnętrzny. Naprawdę mam nadzieję, że nie pozwalasz użytkownikom spoza Twojej firmy korzystać z Twojej aplikacji, ponieważ otworzyłeś ją przed mężczyzną w środkowym ataku i byliby wtedy narażeni na przejęcie sesji przez kogoś. niemniej jednak muszę to zrobić tymczasowo dla niektórych testów, dopóki nie dostanę prawdziwego certyfikatu pod ręką ... mam nadzieję, że robisz to z tego samego powodu lub aplikacja jest używana tylko wewnętrznie.
Dean Hiller,
Wypróbowałem te rozwiązania na kliencie HTTP Apache 4.3, ale są one w większości przestarzałe. To nie jest przestarzałe rozwiązanie: stackoverflow.com/a/18941950/2039471
Alexander Chzhen
Java 1.6 nie obsługuje SNI, co również jest problematyczne w tych scenariuszach - jeśli nie zbudujesz poprawnie żądania, możesz uzyskać certyfikat, który nie pasuje do żądania. Patrz problemy.apache.org/jira/browse/HTTPCLIENT-1119
Bron Davies
2
To pytanie jest cytowane w artykule Najbardziej niebezpieczny kodeks na świecie jako przykład błędnego rozumowania. (artykuł badawczy: cs.utexas.edu/~shmat/shmat_ccs12.pdf )
mk_

Odpowiedzi:

421

Uwaga: Nie implementuj tego w kodzie produkcyjnym, którego będziesz używać w sieci, której nie do końca ufasz. Zwłaszcza wszystko, co dzieje się w publicznym Internecie.

Twoje pytanie jest właśnie tym, co chcę wiedzieć. Po przeprowadzeniu kilku wyszukiwań wniosek jest następujący.

W sposób HttpClient powinieneś utworzyć niestandardową klasę z org.apache.http.conn.ssl.SSLSocketFactory, a nie z samej org.apache.http.conn.ssl.SSLSocketFactory. Kilka wskazówek można znaleźć w tym poście Niestandardowa obsługa SSL przestała działać na Androidzie 2.2 FroYo .

Przykład jest jak ...

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

i użyj tej klasy podczas tworzenia instancji 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, poniższy link jest dla kogoś, kto szuka rozwiązania HttpURLConnection. Połączenie HTTP Android

Przetestowałem powyższe dwa rodzaje rozwiązań na froyo i wszystkie one działają jak urok w moich przypadkach. Wreszcie użycie HttpURLConnection może napotkać problemy z przekierowaniem, ale jest to poza tematem.

Uwaga: zanim zdecydujesz się zaufać wszystkim certyfikatom, prawdopodobnie powinieneś dobrze poznać witrynę i nie będzie to szkodliwe dla użytkownika końcowego.

Rzeczywiście, ryzyko, które podejmujesz, należy dokładnie rozważyć, w tym wpływ fałszywej strony hakera wspomnianej w poniższych komentarzach, które głęboko doceniłem. W niektórych sytuacjach, chociaż może być trudno dbać o wszystkie certyfikaty, lepiej poznać ukryte wady, aby zaufać im wszystkim.

Daniel
źródło
150
ta odpowiedź powinna prawdopodobnie zauważyć, że ufanie wszystkim certyfikatom jest strasznie niepewne i niweczy cały cel ssl ...
yanokwa
22
@sweeney - z wyjątkiem tego, że nie ma gwarancji, że rozmawiasz z serwerem, o którym myślisz, że jesteś. Jeśli ktoś zepsuł serwer DNS, być może komunikujesz klucz szyfrujący z serwerem hakera.
Richard Szalay,
12
@sweeney Innymi słowy, jesteś teraz podatny na ataki typu man-in-the-middle. Należy również zauważyć, że ten kod nie spełnia specyfikacji: sprawdź Javadoc. getAcceptedIssuers()nie można zwrócić null.
Markiz Lorne
25
-1 Ponieważ zaakceptowanie wszystkich certyfikatów jest okropnym pomysłem. Szkoda, że ​​jest tak wiele blogów i samouczków, które z radością prowadzą programistów Java na ścieżce robienia niewłaściwych rzeczy.
Tim Bender
57
+1 Ponieważ potrzebowałem szybkiego rozwiązania wyłącznie do celów debugowania. Nie używałbym tego w produkcji ze względu na obawy dotyczące bezpieczeństwa, o których wspominali inni, ale tego właśnie potrzebowałem do testowania. Dziękuję Ci!
Danation
495

Zasadniczo masz cztery potencjalne rozwiązania, aby naprawić wyjątek „Niezaufany” w Androidzie za pomocą httpclient:

  1. Zaufaj wszystkim certyfikatom. Nie rób tego, chyba że naprawdę wiesz, co robisz.
  2. Utwórz niestandardowy obiekt SSLSocketFactory, który ufa tylko Twojemu certyfikatowi. Działa to tak długo, jak dokładnie wiesz, z którymi serwerami chcesz się połączyć, ale gdy tylko będziesz musiał połączyć się z nowym serwerem z innym certyfikatem SSL, musisz zaktualizować aplikację.
  3. Utwórz plik kluczy, który zawiera „główną listę” certyfikatów Androida, a następnie dodaj własny. Jeśli któreś z tych certyfikatów wygasną w późniejszym okresie, jesteś odpowiedzialny za ich aktualizację w swojej aplikacji. Nie mogę wymyślić żadnego powodu, aby to zrobić.
  4. Utwórz niestandardowy obiekt SSLSocketFactory, który korzysta z wbudowanego certyfikatu KeyStore, ale opiera się na alternatywnym magazynie kluczy dla wszystkiego, czego nie można zweryfikować przy użyciu wartości domyślnej.

Ta odpowiedź wykorzystuje rozwiązanie nr 4, które wydaje mi się najbardziej niezawodne.

Rozwiązaniem jest użycie SSLSocketFactory, który może akceptować wiele KeyStores, umożliwiając dostarczanie do własnego magazynu kluczy własnych certyfikatów. Umożliwia to ładowanie dodatkowych certyfikatów najwyższego poziomu, takich jak Thawte, których może brakować na niektórych urządzeniach z Androidem. Umożliwia także ładowanie własnych certyfikatów z podpisem własnym. Najpierw użyje wbudowanych domyślnych certyfikatów urządzeń, a w razie potrzeby skorzysta z dodatkowych certyfikatów.

Najpierw musisz ustalić, którego certyfikatu brakuje w magazynie kluczy. Uruchom następujące polecenie:

openssl s_client -connect www.yourserver.com:443

Zobaczysz dane wyjściowe takie jak:

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

Jak widać, nasz certyfikat główny pochodzi od Thawte. Przejdź do strony internetowej swojego dostawcy i znajdź odpowiedni certyfikat. Dla nas był tutaj i widać, że potrzebowaliśmy tego, który dotyczy prawa autorskiego 2006.

Jeśli używasz certyfikatu z podpisem własnym, nie musiałeś wykonywać poprzedniego kroku, ponieważ masz już certyfikat podpisu.

Następnie utwórz plik magazynu kluczy zawierający brakujący certyfikat podpisywania. Crazybob ma szczegółowe informacje, jak to zrobić na Androidzie , ale pomysł jest następujący:

Jeśli jeszcze go nie masz, pobierz bibliotekę dostawców dmuchanego zamku ze strony: http://www.bouncycastle.org/latest_releases.html . To pójdzie na twoją ścieżkę klasy poniżej.

Uruchom polecenie, aby wyodrębnić certyfikat z serwera i utworzyć plik pem. W tym przypadku mycert.pem.

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

Następnie uruchom następujące polecenia, aby utworzyć magazyn kluczy.

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

Zauważysz, że powyższy skrypt umieszcza wynik res/raw/mystore.bks. Teraz masz plik, który załadujesz do aplikacji na Androida, który zawiera brakujące certyfikaty.

Aby to zrobić, zarejestruj swój SSLSocketFactory dla schematu 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);

Aby utworzyć 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);
    }
}

Na koniec kod AdditionalKeyStoresSSLSocketFactory, który akceptuje nowy magazyn kluczy i sprawdza, czy wbudowany magazyn kluczy nie sprawdza poprawności certyfikatu 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
źródło
Hej @emmby, wydaje się to idealna odpowiedź na mój problem, ale nadal nie mam połączenia SSL. Czy możesz na to spojrzeć? http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
Matthias B,
Dzięki za wspaniały napis @emmby! Czasami dostaję naprawdę duże opóźnienie, a następnie javax.net.ssl.SSLException: Błąd odczytu :. Dowolny pomysł? Jak ustawić limit czasu, jeśli rozwiązanie jest takie samo jak stackoverflow.com/questions/5909308/android-2-3-4-ssl-problem ?
Edwin Evans,
3
@emmby, czy możesz powiedzieć, gdzie powinienem umieścić ten kod eksportu CLASSPATH = bcprov-jdk16-145.jar CERTSTORE = res / raw / mystore.bks if [-a $ CERTSTORE]; następnie 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
Cześć @emmby. Korzystam z twojego rozwiązania w mojej aplikacji i używam samopodpisanego certyfikatu mojego serwera, ale otrzymuję CertificateException () w metodzie checkServerTrusted () . Próbowałem skomentować ten wyjątek dotyczący rzucania i działa. jeśli nie potwierdzi mojego certyfikatu serwera, czy mogę go obsłużyć w inny sposób, czy możesz wskazać najlepsze rozwiązanie w tym przypadku?
Ankit
7
Należy to zaznaczyć jako właściwą odpowiedź. Jedna z najbardziej dokładnych i dobrze napisanych odpowiedzi, jakie kiedykolwiek widziałem na SO. Dope
Kachi
74

Dodaj ten kod przed HttpsURLConnectioni będzie gotowe. Mam to.

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

Mam nadzieję, że to Ci pomoże.

Alok Gupta
źródło
22
Zobacz uwagi powyżej pod przyjętą odpowiedzią. To „rozwiązanie” jest całkowicie niepewne.
Markiz Lorne
5
To idealne rozwiązanie Q&D. Krótkie i „po prostu działa”.
Steve Smith
5
Idealna odpowiedź do celów testowych !!! I tak, jest to zły pomysł do wykorzystania w produkcji, ale daj spokój ... to powinno być jasne dla wszystkich, którzy patrzą na tytuł pytania. Nadal odpowiada najlepiej / najkrócej / z tym samym (nie) poziomem bezpieczeństwa!
Lewita
34

To jest zły pomysł. Zaufanie do dowolnego certyfikatu jest tylko (bardzo) nieco lepsze niż wcale nie używanie SSL. Kiedy mówisz „Chcę, aby mój klient zaakceptował dowolny certyfikat (ponieważ zawsze wskazuję tylko jeden serwer)”, zakładasz, że oznacza to, że w jakiś sposób wskazanie „jednego serwera” jest bezpieczne, a nie jest to sieć publiczna.

Jesteś całkowicie otwarty na atak typu man-in-the-middle, ufając dowolnemu certyfikatowi. Każdy może proxy Twojego połączenia, ustanawiając osobne połączenie SSL z Tobą i z serwerem końcowym. MITM ma wówczas dostęp do całego żądania i odpowiedzi. Chyba że tak naprawdę nie potrzebujesz protokołu SSL (twoja wiadomość nie ma nic poufnego i nie wykonuje uwierzytelnienia), nie powinieneś ufać ślepo wszystkim certyfikatom.

Powinieneś rozważyć dodanie publicznego certyfikatu do jks za pomocą keytool i użycie go do zbudowania fabryki gniazd, na przykład:

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

To jedno zastrzeżenie, na które należy uważać. Certyfikat ostatecznie wygaśnie, a kod przestanie działać w tym czasie. Możesz łatwo ustalić, kiedy to nastąpi, patrząc na certyfikat.

Dan
źródło
5
Jeśli nie używasz uwierzytelniania za pomocą certyfikatu klienta, po stronie klienta nie potrzebujesz menedżera kluczy (użyj nullw SSLContext.init). You should also use the default algorithms (KMF/TMF.getDefaultAlgorithm() ), instead of hard-coding SunX509` (tym bardziej, że domyślną wartością TMF jest w rzeczywistości PKIXSun / Oracle JVM).
Bruno
Czy istnieje gotowy do użycia plik certyfikatów głównych? (podobnie jak przeglądarki)
Dani Herrera
Skąd myjks.jkspochodzi?
zionpi
1
@zionpi Wygenerowano przy użyciu Java „keytool”.
Dan
22

Możesz wyłączyć sprawdzanie SSL HttpURLConnection dla celów testowych w ten sposób od 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
źródło
2
org.apache.http.conn.ssl.AllowAllHostnameVerifierjest przestarzałe.
zackygaurav
2
@zackygaurav Według javadoc , AllowAllHostnameVerifierzostaje zastąpiony przez NoopHostnameVerifier
DLight
10

Interfejs API HttpComponents został zmieniony. Działa z kodem poniżej.

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
źródło
Użycie niestandardowej strategii zaufania jest właściwą odpowiedzią. Dzięki.
Matt Friedman,
10

Powyższy kod w https://stackoverflow.com/a/6378872/1553004 jest poprawny, ale MUSI także wywoływać weryfikator nazwy hosta:

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

Zapisałem się wyraźnie do Stackoverflow, aby dodać tę poprawkę. Posłuchaj mojego ostrzeżenia!

Robert Blair
źródło
Po zweryfikowaniu certyfikatu w ten sposób przy pierwszym połączeniu, co robisz z kolejnymi połączeniami? Czy wykorzystujesz wiedzę zdobytą podczas pierwszego połączenia? Co jeśli fałszywy certyfikat o tej samej nazwie zostanie użyty przy próbie połączenia 3?
jww
6

Dodaję odpowiedź dla tych, którzy używają httpclient-4.5 i prawdopodobnie działa również dla 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);
    }
}
}
raisercostin
źródło
czym jest nowa klasa NoopHostnameVerifier ()?
Mushtakim Ahmed Ansari
1
@MushtakimAhmedAnsari Z dokumentów: „NO_OP HostnameVerifier zasadniczo wyłącza weryfikację nazwy hosta. Ta implementacja nie działa i nigdy nie zgłasza SSLException”.
raisercostin
Dzięki za świetną odpowiedź. Ten powinien uzyskać więcej głosów.
Abhay Dwivedi
Jak z tego korzystać? lub sugerujesz, że sama klasa zastąpi weryfikację certyfikatu ssl?
behelit
tak. ten httpClient, jeśli zostanie użyty, nie zweryfikuje certyfikatów https
raisercostin
4

Ufanie wszystkim certyfikatom nie było dla mnie prawdziwą alternatywą, więc zrobiłem następujące, aby uzyskać HttpsURLConnection, aby zaufać nowemu certyfikatowi (patrz również http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store- on.html ).

  1. Zdobądź certyfikat; Zrobiłem to, eksportując certyfikat do Firefoksa (kliknij małą ikonę kłódki, uzyskaj szczegóły certyfikatu, kliknij eksportuj), a następnie użyłem portecle do wyeksportowania magazynu zaufanych certyfikatów (BKS).

  2. Załaduj magazyn zaufanych certyfikatów z /res/raw/geotrust_cert.bks następującym kodem:

        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
źródło
Otrzymuję ten błąd. IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate. Dzieje się tak podczas wykonywania rzeczywistego wywołania na HttpClient po wykonaniu powyższej konfiguracji.
Michael
3

Oto bardzo prosta wersja wykorzystująca kod httpclient 4.1.2. Można to następnie zmienić na dowolny algorytm zaufania, który uważasz za odpowiedni.

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
źródło
3

Spojrzałem na odpowiedź z „emmby” (odpowiedź 16 czerwca o 21:29), punkt 4: „Utwórz niestandardowy obiekt SSLSocketFactory, który korzysta z wbudowanego certyfikatu KeyStore, ale wraca do alternatywnego magazynu kluczy dla wszystkiego, co się nie powiedzie zweryfikować z ustawieniem domyślnym. ”

To jest uproszczone wdrożenie. Załaduj systemowy magazyn kluczy i połącz go z magazynem kluczy aplikacji.

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

Prosty tryb konwersji z JKS na 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

* Uwaga: w Androidzie 4.0 (ICS) Trust Store zmienił się, więcej informacji: http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html

Grgrandes
źródło
3

Dla tych, którzy chcieliby zezwolić na działanie wszystkich certyfikatów (do celów testowych) przez OAuth, wykonaj następujące kroki:

1) Pobierz kod źródłowy interfejsu API Androida OAuth tutaj: https://github.com/kaeppler/signpost

2) Znajdź plik „CommonsHttpOAuthProvider”

3) Zmień to jak poniżej:

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

Powyższy „MySSLSocketFactory” opiera się na zaakceptowanej odpowiedzi. Aby było jeszcze łatwiej, oto cała klasa:

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

}

Mam nadzieję, że to komuś pomoże.

Tiago
źródło
1
Pytanie brzmiało HttpClienti HTTPS; nie OAuth dla Androida z projektu GitHub.
jww
3

Użyłem tego i działa na mnie na wszystkich systemach operacyjnych.

/**
 * 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
źródło
Witaj @ yegor256, używam tego kodu, ale wciąż
pojawia się
0

Każdy organ, który wciąż ma problemy z certyfikatami StartCom SSL na Androida 2.1, odwiedza https://www.startssl.com/certs/ i pobiera plik ca.pem, teraz w odpowiedzi udzielonej przez @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`

z

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

Powinien działać po wyjęciu z pudełka. Walczyłem z tym przez ponad dzień, nawet po doskonałej odpowiedzi @emmby .. Mam nadzieję, że to pomaga komuś ...

13hsoj
źródło
0

użyj tej klasy

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
źródło
0

wprowadź opis zdjęcia tutaj

SSPI nie powiodło się w Xamarin Android.

Znalazłem to rozwiązanie; umieść ten kod, zanim klikniesz link HTTPS

const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;
vinothswami
źródło
-3

pracować ze wszystkimi 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
źródło
2
Po prostu powtarza to samo błędne, niepewne rozwiązanie, które zostało już omówione i odrzucone w tym wątku.
Markiz Lorne
-3

Istnieje wiele odpowiedzi powyżej, ale nie byłem w stanie sprawić, by żadna z nich działała poprawnie (z moim ograniczonym czasem), więc dla każdego innego w tej samej sytuacji możesz wypróbować kod, który działał idealnie dla moich celów testowania 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;
    }
}

i zadzwoń jak:

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

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

pozorny
źródło
Cytując EJP: „Po prostu powtarza to samo błędne niepewne nierozwiązanie, które zostało już omówione i odrzucone w tym wątku” .
jww
-4

Po prostu użyj tego -

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
źródło
Cytując EJP: „Po prostu powtarza to samo błędne niepewne nierozwiązanie, które zostało już omówione i odrzucone w tym wątku” .
jww
-5

Odpowiedź Daniela była dobra, tyle że musiałem zmienić ten kod ...

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

do tego kodu ...

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

żeby to zadziałało.

Dean Hiller
źródło
5
jak to powinno działać? odwołujesz się do rejestru, zanim jeszcze go utworzyłeś!
Matthias B,