Nie znaleziono kotwicy zaufania dla połączenia SSL systemu Android

185

Próbuję połączyć się z urządzeniem IIS6 z uruchomionym certyfikatem 256-bitowym certyfikatem chrzestnym SSL i pojawia się błąd:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

Próbowałem ustalić, co może być przyczyną, ale teraz rysuję puste.

Oto jak się łączę:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream()); 
Chrispix
źródło

Odpowiedzi:

78

Rozwiązanie @Chrispix jest niebezpieczne! Zaufanie do wszystkich certyfikatów pozwala każdemu wykonać człowieka w środku ataku!Wystarczy wysłać DOWOLNY certyfikat do klienta, a on go zaakceptuje!

Dodaj swoje certyfikaty do niestandardowego menedżera zaufania, jak opisano w tym poście: Ufanie wszystkim certyfikatom za pomocą HttpClient przez HTTPS

Chociaż ustanowienie bezpiecznego połączenia z niestandardowym certyfikatem jest nieco bardziej skomplikowane, przyniesie Ci pożądane bezpieczeństwo szyfrowania ssl bez niebezpieczeństwa człowieka w środku ataku!

Matthias B.
źródło
1
Jest to odpowiednie do pracy z samodzielnie wygenerowanym certyfikatem, ale dla jednego (takiego jak OP), który ma prawidłowy łańcuch z powrotem do głównego urzędu certyfikacji, jest to tylko obejście dla źle skonfigurowanego serwera - zobacz moją odpowiedź.
Stevie,
4
@Stevie Akceptacja KAŻDEGO certyfikatu jest tylko opcją testu sprawdzającego koncepcję, gdzie połączenie SSL nie jest częścią, którą chcesz przetestować. W przeciwnym razie nie musisz używać protokołu SSL, jeśli akceptujesz każdy certyfikat, ponieważ połączenie nie jest bezpieczne!
Matthias B
1
Ach, przepraszam, myślę, że istnieje nieporozumienie - całkowicie się zgadzam, że nikt nigdy nie powinien akceptować każdego certyfikatu! :) Mój komentarz dotyczył twojego drugiego akapitu - sugestii użycia niestandardowego menedżera zaufania - który IMHO powinien być rozwiązaniem ostatecznym, a nie zalecanym rozwiązaniem.
Stevie,
2
Po pierwsze, usunąłem „rozwiązanie”, które wkleiłem jako obejście, aby nie powodować więcej problemów, ponieważ ludzie nie postrzegali go jako „tymczasowe obejście”.
Chrispix,
7
@Chrispix, nie powinieneś był usuwać częściowej poprawki, jest ona dobra tylko do celów testowych
Hugo Allexis Cardona
224

W przeciwieństwie do przyjętej odpowiedzi, nie potrzebujesz niestandardowego menedżera zaufania, musisz naprawić konfigurację serwera!

Uderzyłem ten sam problem podczas łączenia się z serwerem Apache z niepoprawnie zainstalowanym certyfikatem dynadot / alphassl. Łączę się za pomocą HttpsUrlConnection (Java / Android), który rzucał -

javax.net.ssl.SSLHandshakeException: 
  java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

Rzeczywistym problemem jest błędna konfiguracja serwera - przetestuj go http://www.digicert.com/help/ lub podobnej, a nawet podpowie Ci rozwiązanie:

„Certyfikat nie jest podpisany przez zaufany organ (porównanie z głównym sklepem Mozilli). Jeśli kupiłeś certyfikat od zaufanego organu, prawdopodobnie po prostu musisz zainstalować jeden lub więcej certyfikatów pośrednich . Skontaktuj się z dostawcą certyfikatu, aby uzyskać pomoc platforma serwera ”.

Możesz także sprawdzić certyfikat za pomocą openssl:

openssl s_client -debug -connect www.thedomaintocheck.com:443

Prawdopodobnie zobaczysz:

Verify return code: 21 (unable to verify the first certificate)

i wcześniej w danych wyjściowych:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

Łańcuch certyfikatów będzie zawierał tylko 1 element (twój certyfikat):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

... ale powinien odwoływać się do organów podpisujących w łańcuchu z powrotem do zaufanego systemu Android (Verisign, GlobalSign itp.):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

Instrukcje (i certyfikaty pośrednie) dotyczące konfigurowania serwera są zwykle dostarczane przez organ, który wystawił certyfikat, na przykład: http://www.alphassl.com/support/install-root-certificate.html

Po zainstalowaniu certyfikatów pośrednich dostarczonych przez mojego wystawcę certyfikatu nie mam teraz błędów podczas łączenia za pomocą HttpsUrlConnection.

Stevie
źródło
3
W przypadku, gdy OP ma dostęp do konfiguracji SSL serwerów, z którą się łączy, może to być rozwiązanie. Ale jeśli to nie on hostuje usługę, z którą się łączy, musi rozwiązać problem po swojej stronie, co oznacza wdrożenie niestandardowego menedżera zaufania.
Matthias B
9
Twoje rozwiązanie działa bez wątpienia, ale czy nie zgadzasz się, że jest to obejście, a nie poprawka dla podstawowej przyczyny? Jeśli muszę połączyć się z serwerem z 3 klientów (Android, iOS, Windows Mobile), muszę zastosować obejście na wszystkich 3, podczas gdy mogę naprawić serwer raz, a one wszystkie „po prostu działają”.
Stevie,
2
Dzięki Stevie, przez 3 miesiące źle skonfigurowałem mój serwer i dopiero teraz to wykryłem! Teraz moja aplikacja na Androida działa w 100%
jpros
2
@Stevie Wykonuję wiele wywołań do różnych interfejsów API, które dzielą tę samą domenę, ale tylko jeden z nich kończy się niepowodzeniem (javax.net.ssl.SSLHandshakeException) ... jakiś pomysł, dlaczego tak się stanie? a przy okazji, certyfikat SSL nie jest zaufany. Pomyślałem więc, że wszystkie połączenia powinny zakończyć się niepowodzeniem z tym samym wyjątkiem.
uczciwy gracz
1
@dvaey skontaktuj się z kimkolwiek, kto jest właścicielem serwera i powiedz mu, że ich konfiguracja jest zepsuta, a ich https nie działa poprawnie - daj im ten link, aby to udowodnić digicert.com/help ... Wyobrażam sobie, że byliby wdzięczni i szybko rozwiązać. W przeciwnym razie musisz wykonać jeden z kroków obejścia w innych odpowiedziach, ale wtedy albo nie zaakceptujesz zabezpieczeń (zignoruj ​​certyfikaty), albo ponownie wdrożysz aplikacje, gdy wygasa certyfikat i Twój niestandardowy magazyn zaufania nie pasuje już do nowego cert.
Stevie,
17

Możesz zaufać konkretnemu certyfikatowi w czasie wykonywania.
Wystarczy pobrać go z serwera, włożyć zasoby i załadować w ten sposób przy użyciu ssl-utils-android :

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

W powyższym przykładzie użyłem OkHttpClientaleSSLContext można go używać z dowolnym klientem w Javie.

Jeśli masz jakieś pytania, możesz je zadać. Jestem autorem tej małej biblioteki.

klimat
źródło
co z .pfx?
Choletski
2
Czy to nie jest niebezpieczne, ponieważ każdy użytkownik może uzyskać dostęp do folderu zasobów dla aplikacji, gdy ma już apk?
Patrice Andala,
1
@PatriceAndala, główne urzędy certyfikacji są publicznie dostępne, więc jest w porządku
BekaBot
17

Aktualizacja na podstawie najnowszej dokumentacji Androida (marzec 2017 r.):

Gdy pojawi się ten typ błędu:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
        at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

problem może być jednym z następujących:

  1. Urząd certyfikacji, który wystawił certyfikat serwera, był nieznany
  2. Certyfikat serwera nie został podpisany przez urząd certyfikacji, ale został podpisany przez siebie
  3. W konfiguracji serwera brakuje pośredniego urzędu certyfikacji

Rozwiązaniem jest nauczenie HttpsURLConnectionzaufania do określonego zestawu urzędów certyfikacji. W jaki sposób? Sprawdź https://developer.android.com/training/articles/security-ssl.html#CommonProblems

Inni, którzy korzystają AsyncHTTPClientz com.loopj.android:android-async-httpbiblioteki, sprawdź Setup AsyncHttpClient, aby korzystać z HTTPS .

użytkownik1506104
źródło
5
Co jeśli ktoś korzysta z klienta HTTP?
TheLearner,
Dla okhttp, proszę sprawdzić odpowiedź @ mklimek.
user1506104,
14

Jeśli używasz modernizacji, musisz dostosować swojego OkHttpClient.

retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

Pełny kod jest jak poniżej.

    public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ApiInterface getApiClient() {
        if (apiInterface == null) {

            try {
                retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

            } catch (Exception e) {

                e.printStackTrace();
            }


            apiInterface = retrofit.create(ApiInterface.class);
        }
        return apiInterface;
    }

}
Shihab Uddin
źródło
1
Próbuję użyć kodu, ale ponownie pojawia się następujący błąd. „Wyjątek javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Nie znaleziono kotwicy zaufania dla ścieżki certyfikacji.” czy możesz w tym pomóc
Vishwa Pratap
Jest to całkowicie niepewne. Nie używać.
Markiz Lorne
Dzięki! Ponownie przepisaj metodę getUnsafeOkHttpClient()w Kotlin: stackoverflow.com/a/60507560/2914140 .
CoolMind
11

Odpowiadanie na bardzo stary post. Ale może pomoże to nowicjuszowi, a jeśli nie spełni powyższego warunku.

Wyjaśnienie: Wiem, że nikt nie chce bzdur wyjaśnienia; raczej rozwiązanie. Ale w jednym pakiecie próbujesz uzyskać dostęp do usługi z komputera lokalnego na maszynie zdalnej, która nie ufa twojemu komputerowi. Żądanie wymaga zaufania od zdalnego serwera.

Rozwiązanie: następujące rozwiązanie zakłada, że ​​spełnione są następujące warunki

  1. Próbujesz uzyskać dostęp do zdalnego interfejsu API z lokalnego komputera.
  2. Budujesz dla aplikacji na Androida
  3. Twój zdalny serwer jest w trakcie filtrowania proxy (używasz proxy w ustawieniach przeglądarki, aby uzyskać dostęp do zdalnej usługi interfejsu API, zazwyczaj serwera przejściowego lub deweloperskiego)
  4. Testujesz na prawdziwym urządzeniu

Kroki:

Potrzebujesz pliku rozszerzenia .keystore, aby zarejestrować swoją aplikację. Jeśli nie wiesz, jak utworzyć plik .keystore; następnie postępuj zgodnie z następującą sekcją Utwórz plik .keystore lub w inny sposób przejdź do następnej sekcji Podpisz plik APK

Utwórz plik .keystore

Otwórz Android Studio. Kliknij menu główne Kompilacja> Wygeneruj podpisany plik APK. W następnym oknie kliknij przycisk Utwórz nowe ... przycisk. W nowym oknie wprowadź dane we wszystkich polach. Zapamiętaj dwa pola Hasło, które polecam, powinno mieć to samo hasło; nie używaj innego hasła; a także zapamiętać ścieżkę zapisu w skrajnym górnym polu magazynu kluczy ścieżce: . Po wprowadzeniu wszystkich pól kliknij przycisk OK.

Podpisz plik APK

Teraz musisz zbudować podpisaną aplikację z właśnie utworzonego pliku .keystore. Wykonaj następujące kroki

  1. Zbuduj> Wyczyść projekt, poczekaj, aż zakończy czyszczenie
  2. Kompilacja> Generuj podpisany APK
  3. Kliknij Choose existing...przycisk
  4. Wybierz właśnie utworzony plik .keystore w sekcji Utwórz plik .keystore
  5. Wprowadź to samo hasło, które utworzyłeś podczas tworzenia w sekcji Utwórz plik .keystore . Użyj tego samego hasła Key store passwordi Key passwordpól. Wprowadź także alias
  6. Kliknij przycisk Dalej
  7. Na następnym ekranie; które mogą się różnić w zależności od ustawień w build.gradleplikach, musisz wybrać Build Typesi Flavors.
  8. Do Build Typeswyboru releasez menu rozwijanego
  9. Na Flavorsto jednak będzie, zależy od ustawień w build.gradlepliku. Wybierz stagingz tego pola. Użyłem następujących ustawień w build.gradle, możesz użyć tego samego co moje, ale upewnij się, że zmieniłeś applicationIdnazwę pakietu

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
  10. Kliknij dwa dolne Signature Versionspola wyboru i kliknij Finishprzycisk.

Prawie na miejscu:

Cała ciężka praca została wykonana, teraz ruch prawdy. Aby uzyskać dostęp do serwera pomostowego z kopią zapasową utworzoną przez serwer proxy, musisz wprowadzić pewne ustawienia w rzeczywistych testujących urządzeniach z Androidem.

Ustawienie proxy w urządzeniu z Androidem:

  1. Kliknij ustawienie wewnątrz telefonu z Androidem, a następnie Wi-Fi
  2. Naciśnij i przytrzymaj podłączone WiFi i wybierz Modify network
  3. Kliknij, Advanced optionsjeśli nie widziszProxy Hostname pola
  4. W Proxy Hostnamewprowadź adres IP lub nazwę hosta chcesz się połączyć. Typowy serwer pomostowy zostanie nazwany jakostg.api.mygoodcompany.com
  5. Dla portu wpisz na przykład czterocyfrowy numer portu 9502
  6. Naciśnij Saveprzycisk

Ostatni przystanek:

Pamiętaj, że wygenerowaliśmy podpisany plik apk w sekcji Zarejestruj plik APK . Nadszedł czas, aby zainstalować ten plik APK.

  1. Otwórz terminal i przejdź do podpisanego folderu plików apk
  2. Podłącz urządzenie z Androidem do swojego komputera
  3. Usuń wcześniej zainstalowany plik apk z urządzenia z Androidem
  4. Biegać adb install name of the apk file
  5. Jeśli z jakiegoś powodu powyższe polecenie powróci za pomocą adb command not found. Wpisz pełną ścieżkę jakoC:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe install name of the apk file

Mam nadzieję, że problem może zostać rozwiązany. Jeśli nie, proszę zostawić komentarz.

Salam!

HA S
źródło
4

Komunikat o błędzie, który otrzymywałem, był podobny, ale przyczyną był fakt, że certyfikat z podpisem własnym wygasł. Gdy podjęto próbę klienta openssl, podał mi powód, który został przeoczony, kiedy sprawdzałem okno dialogowe certyfikatu z firefox.

Ogólnie rzecz biorąc, jeśli certyfikat znajduje się w magazynie kluczy i jego „WAŻNY”, ten błąd zgaśnie.

MPN
źródło
1
Jeśli certyfikat wygasł, jest nieważny zgodnie z wieloma standardami. Można użyć niestandardowego TrustManageri innego zestawu kryteriów. Ale od razu po tym musisz pracować.
jww
4

Miałem ten sam problem podczas łączenia się z klienta Android na serwerze Kurento. Serwer Kurento używa certyfikatów jks, więc musiałem przekonwertować na niego PEM. Jako dane wejściowe do konwersji użyłem pliku cert.pem i prowadzi to do takich błędów. Ale jeśli użyjesz fullchain.pem zamiast cert.pem - wszystko jest w porządku.

V.Poddubchak
źródło
3

Skorzystaj z https://www.ssllabs.com/ssltest/ aby przetestować domenę.

Rozwiązanie Shihab Uddin w Kotlin.

import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException

companion object {

    private val gson: Gson
    private val retrofit: Retrofit

    init {

        val okHttpClient = getUnsafeOkHttpClient() // OkHttpClient().newBuilder()
            .build()

        gson = GsonBuilder().setLenient().create()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }

    private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                }
            )
            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory,
                trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { _, _ -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}
CoolMind
źródło
2

Miałem ten sam problem, co znalazłem, to że podany plik certyfikatu .crt brakuje certyfikatu pośredniego. Poprosiłem więc wszystkie pliki .crt od mojego administratora serwera, a następnie skonfliktowałem je w odwrotnej kolejności.

Dawny. 1. Root.crt 2. Inter.crt 3. myCrt.crt

w systemie Windows wykonałem kopię Inter.crt + Root.crt newCertificate.crt

(Tutaj zignorowałem myCrt.crt)

Następnie podałem plik newCertificate.crt do kodu poprzez inputstream. Robota wykonana.

Sahan Maldeniya
źródło
Mieliśmy również ten sam problem. Brak certyfikatu pośredniego
Nidhin Chandran
1

Błąd zakotwiczenia zaufania może wystąpić z wielu powodów. Dla mnie po prostu próbowałem uzyskać dostęp https://example.com/zamiasthttps://www.example.com/ .

Możesz więc sprawdzić dwa razy swoje adresy URL, zanim zaczniesz budować własnego Trust Managera (tak jak ja).

Unkulunkulu
źródło
0

W telefonach z piernikiem zawsze pojawia się ten błąd: Trust Anchor not found for Android SSL Connection nawet jeśli skonfiguruję poleganie na moim certyfikacie.

Oto kod, którego używam (w języku Scala):

object Security {
    private def createCtxSsl(ctx: Context) = {
        val cer = {
            val is = ctx.getAssets.open("mycertificate.crt")
            try
                CertificateFactory.getInstance("X.509").generateCertificate(is)
            finally
                is.close()
        }
        val key = KeyStore.getInstance(KeyStore.getDefaultType)
        key.load(null, null)
        key.setCertificateEntry("ca", cer)

        val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    tmf.init(key)

        val c = SSLContext.getInstance("TLS")
        c.init(null, tmf.getTrustManagers, null)
        c
    }

    def prepare(url: HttpURLConnection)(implicit ctx: Context) {
        url match {
            case https: HttpsURLConnection 
                val cSsl = ctxSsl match {
                    case None 
                        val res = createCtxSsl(ctx)
                        ctxSsl = Some(res)
                        res
                    case Some(c)  c
                }
                https.setSSLSocketFactory(cSsl.getSocketFactory)
            case _ 
        }
    }

    def noSecurity(url: HttpURLConnection) {
        url match {
            case https: HttpsURLConnection 
                https.setHostnameVerifier(new HostnameVerifier {
                    override def verify(hostname: String, session: SSLSession) = true
                })
            case _ 
        }
    }
}

a oto kod połączenia:

def connect(securize: HttpURLConnection  Unit) {
    val conn = url.openConnection().asInstanceOf[HttpURLConnection]
    securize(conn)
    conn.connect();
    ....
}

try {
    connect(Security.prepare)
} catch {
    case ex: SSLHandshakeException /*if ex.getMessage != null && ex.getMessage.contains("Trust anchor for certification path not found")*/ 
        connect(Security.noSecurity)
}

Zasadniczo konfiguruję zaufanie do mojego certyfikatu niestandardowego. Jeśli to się nie powiedzie, wyłączam zabezpieczenia. To nie jest najlepsza opcja, ale jedyny wybór, jaki znam ze starymi i wadliwymi telefonami.

Ten przykładowy kod można łatwo przetłumaczyć na Javę.

david.perez
źródło
Rozwiązanie dla Androida 2.3.x na wypadek, gdyby ktoś tego potrzebował, stackoverflow.com/a/46465722/7125370
Newbie009
0

W moim przypadku działo się tak po aktualizacji do Androida 8.0. Samopodpisany certyfikat systemu Android, któremu ufano, korzystał z algorytmu podpisu SHA1wRSRS. Przejście na nowy certyfikat za pomocą algorytmu podpisu SHA256wRSRS rozwiązało problem.

Zds
źródło
0

Wiem, że nie musisz ufać wszystkim certyfikatom, ale w moim przypadku miałem problemy z niektórymi środowiskami debugowania, w których mieliśmy certyfikaty z podpisem własnym i potrzebowałem brudnego rozwiązania.

Wszystko, co musiałem zrobić, to zmienić inicjalizację pliku sslContext

mySSLContext.init(null, trustAllCerts, null); 

gdzie trustAllCertszostał stworzony w ten sposób:

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

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

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

Mam nadzieję, że to się przyda.

Adrian C.
źródło
To chciałem znaleźć! Dzięki
oksydowany
Dostaję błąd Hostname '192.168.0.16' was not verified. Testuję moje webapi lokalnie za pomocą mojego debuggera (IIS Express). Jakiś pomysł jak to naprawić? Dzięki :)
Sam
1
Jest to całkowicie niepewne. Nie używać.
Markiz Lorne
0

Miałem podobny problem i całkowicie wykluczyłem strategię zaufania do wszystkich źródeł.

Tutaj udostępniam moje rozwiązanie zastosowane do aplikacji zaimplementowanej w Kotlinie

Najpierw poleciłbym skorzystanie z następującej strony internetowej w celu uzyskania informacji o certyfikacie i jego ważności

Jeśli nie pojawia się jako „Zaakceptowani wystawcy” w domyślnym magazynie zaufania Androida , musimy uzyskać ten certyfikat i włączyć go do aplikacji, aby utworzyć niestandardowy magazyn zaufania

Idealnym rozwiązaniem w moim przypadku było stworzenie wysokiego poziomu Trust Managera, który łączy niestandardowy i domyślny magazyn zaufania Androida

Tutaj ujawnia kod wysokiego poziomu użyty do skonfigurowania klienta OkHttpClient, którego używał przy modernizacji.

override fun onBuildHttpClient(httpClientBuild: OkHttpClient.Builder) {

        val trustManagerWrapper = createX509TrustManagerWrapper(
            arrayOf(
                getCustomX509TrustManager(),
                getDefaultX509TrustManager()
            )
        )

        printX509TrustManagerAcceptedIssuers(trustManagerWrapper)

        val sslSocketFactory = createSocketFactory(trustManagerWrapper)
        httpClientBuild.sslSocketFactory(sslSocketFactory, trustManagerWrapper)

    }

W ten sposób mogłem komunikować się z serwerem z certyfikatem z podpisem własnym iz innymi serwerami z certyfikatem wydanym przez zaufany podmiot certyfikujący

To jest to, mam nadzieję, że może komuś pomóc.

Sergio Sánchez Sánchez
źródło
0

Wiem, że to bardzo stary artykuł, ale natknąłem się na ten artykuł, próbując rozwiązać problemy z zakotwiczeniem zaufania. Opublikowałem, jak to naprawiłem. Jeśli masz wstępnie zainstalowany główny urząd certyfikacji, musisz dodać konfigurację do manifestu.

https://stackoverflow.com/a/60102517/114265

Wysłannik GR
źródło
tylko dla API 24+
BekaBot
@BekaBot - jest to prawdopodobnie prawda, ale zgodnie z dokumentacją 23 i niższą domyślnie ufaj certyfikatom użytkownika Domyślnie bezpieczne połączenia (wykorzystujące protokoły takie jak TLS i HTTPS) ze wszystkich aplikacji ufają wstępnie zainstalowanym systemowym urzędom certyfikacji i aplikacjom ukierunkowanym na Androida 6.0 (Poziom API 23) i niższy również domyślnie ufają dodanemu przez użytkownika sklepowi CA
GR Envoy
-1
**Set proper alias name**
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
            X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
            String alias = cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
Dayanand Waghmare
źródło
-2

Też napotkałem ten sam problem. Po prostu usuwam hhtps na http, takie jak

final public static String ROOT_URL = "https://example.com"; do final public static String ROOT_URL = "http://example.com";

W końcu rozwiązałem ten problem.

Rasheduzzaman
źródło
Z pewnością jest to po prostu usunięcie zabezpieczeń SSL z równania, co jest prawdopodobnie złym pomysłem dla środowiska produkcyjnego.
Dragonthoughts
To naprawdę nie jest rozwiązanie, usuwając zabezpieczenia SSL.
omega1