Niedawno opublikowałem pytanie dotyczące HttpClient
ponad 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
java
ssl
https
certificate
apache-httpclient-4.x
harrisonlee
źródło
źródło
Odpowiedzi:
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 ...
i użyj tej klasy podczas tworzenia instancji HttpClient.
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.
źródło
getAcceptedIssuers()
nie można zwrócić null.Zasadniczo masz cztery potencjalne rozwiązania, aby naprawić wyjątek „Niezaufany” w Androidzie za pomocą httpclient:
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:
Zobaczysz dane wyjściowe takie jak:
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.
Następnie uruchom następujące polecenia, aby utworzyć magazyn kluczy.
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:
Aby utworzyć SSLSocketFactory:
Na koniec kod AdditionalKeyStoresSSLSocketFactory, który akceptuje nowy magazyn kluczy i sprawdza, czy wbudowany magazyn kluczy nie sprawdza poprawności certyfikatu SSL:
źródło
http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
Dodaj ten kod przed
HttpsURLConnection
i będzie gotowe. Mam to.Mam nadzieję, że to Ci pomoże.
źródło
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:
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.
źródło
null
wSSLContext.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ściPKIX
Sun / Oracle JVM).myjks.jks
pochodzi?Możesz wyłączyć sprawdzanie SSL HttpURLConnection dla celów testowych w ten sposób od API 8:
źródło
org.apache.http.conn.ssl.AllowAllHostnameVerifier
jest przestarzałe.AllowAllHostnameVerifier
zostaje zastąpiony przezNoopHostnameVerifier
„Interfejs API HttpComponents został zmieniony. Działa z kodem poniżej.
źródło
Powyższy kod w https://stackoverflow.com/a/6378872/1553004 jest poprawny, ale MUSI także wywoływać weryfikator nazwy hosta:
Zapisałem się wyraźnie do Stackoverflow, aby dodać tę poprawkę. Posłuchaj mojego ostrzeżenia!
źródło
Dodaję odpowiedź dla tych, którzy używają httpclient-4.5 i prawdopodobnie działa również dla 4.4.
źródło
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 ).
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).
Załaduj magazyn zaufanych certyfikatów z /res/raw/geotrust_cert.bks następującym kodem:
źródło
IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate
. Dzieje się tak podczas wykonywania rzeczywistego wywołania na HttpClient po wykonaniu powyższej konfiguracji.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.
źródło
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.
Prosty tryb konwersji z JKS na BKS:
* 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
źródło
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:
Powyższy „MySSLSocketFactory” opiera się na zaakceptowanej odpowiedzi. Aby było jeszcze łatwiej, oto cała klasa:
}
Mam nadzieję, że to komuś pomoże.
źródło
HttpClient
i HTTPS; nie OAuth dla Androida z projektu GitHub.Użyłem tego i działa na mnie na wszystkich systemach operacyjnych.
źródło
Wystarczy dodać
-Dtrust_all_cert=true
argumenty VM. Ten argument mówi Javie, aby zignorowała sprawdzanie certyfikatów.źródło
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
z
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ś ...
źródło
użyj tej klasy
}
źródło
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
źródło
pracować ze wszystkimi https
źródło
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:
i zadzwoń jak:
Odniesienie: http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-problem-using-apache-httpclient/
źródło
Po prostu użyj tego -
źródło
Odpowiedź Daniela była dobra, tyle że musiałem zmienić ten kod ...
do tego kodu ...
żeby to zadziałało.
źródło