Robię post https i otrzymuję wyjątek wyjątku ssl Niezaufany certyfikat serwera. Jeśli robię normalny http, działa idealnie. Czy muszę jakoś akceptować certyfikat serwera?
Zgaduję, ale jeśli chcesz, aby rzeczywiście nastąpił uścisk dłoni, musisz powiadomić Androida o swoim certyfikacie. Jeśli chcesz zaakceptować bez względu na wszystko, użyj tego pseudokodu, aby uzyskać to, czego potrzebujesz z klientem Apache HTTP:
publicclassCustomSSLSocketFactoryextends org.apache.http.conn.ssl.SSLSocketFactory{privateSSLSocketFactory FACTORY =HttpsURLConnection.getDefaultSSLSocketFactory ();publicCustomSSLSocketFactory(){super(null);try{SSLContext context =SSLContext.getInstance ("TLS");TrustManager[] tm =newTrustManager[]{newFullX509TrustManager()};
context.init (null, tm,newSecureRandom());
FACTORY = context.getSocketFactory ();}catch(Exception e){
e.printStackTrace();}}publicSocket createSocket()throwsIOException{return FACTORY.createSocket();}// TODO: add other methods like createSocket() and getDefaultCipherSuites().// Hint: they all just make a call to member FACTORY }
FullX509TrustManager to klasa, która implementuje javax.net.ssl.X509TrustManager, ale żadna z metod nie wykonuje żadnej pracy, pobierz próbkę tutaj .
return FACTORY.createSocket (); ma problem. Utworzone gniazdo daje zerowy wyjątek Pointer podczas wykonywania funkcji execute (). Zauważyłem również, że istnieją 2 klasy SocketFactory. 1. org.apache.http.conn.ssl.SSLSocketFactory i 2. javax.net.ssl.SSLSocketFactory
Codevalley
2
Cześć Nate, to wygląda na coś pomocnego w mojej sytuacji. Ale mam pewne problemy z tworzeniem CustomSSLSocketFactory. Jaką klasę ma przedłużyć? Albo jaki interfejs ma zaimplementować? Eksperymentowałem z: javax.net.SocketFactory, javax.net.ssl.SSLSocketFactory, org.apache.http.conn.scheme.SocketFactory, z których wszystkie wymuszają implementację innych metod ... Więc ogólnie, co są przestrzenie nazw klas używanych w twoim kodzie? Dziękuję Ci. :)
Cephron
2
Nie działa dla mnie, daje mi ten sam błąd certyfikatu niezaufanego serwera.
Omar Rehman
1
jak mogę dostać tę klasęFullX509TrustManager
RajaReddy PolamReddy
89
To właśnie robię. Po prostu nie sprawdza już certyfikatu.
// always verify the host - dont check for certificatefinalstaticHostnameVerifier DO_NOT_VERIFY =newHostnameVerifier(){publicboolean verify(String hostname,SSLSession session){returntrue;}};/**
* Trust every server - dont check for any certificate
*/privatestaticvoid trustAllHosts(){// Create a trust manager that does not validate certificate chainsTrustManager[] trustAllCerts =newTrustManager[]{new X509TrustManager(){public java.security.cert.X509Certificate[] getAcceptedIssuers(){returnnew java.security.cert.X509Certificate[]{};}publicvoid checkClientTrusted(X509Certificate[] chain,String authType)throwsCertificateException{}publicvoid checkServerTrusted(X509Certificate[] chain,String authType)throwsCertificateException{}}};// Install the all-trusting trust managertry{SSLContext sc =SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts,new java.security.SecureRandom());HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());}catch(Exception e){
e.printStackTrace();}}
To wygląda dobrze! Używam jednak WebView i muszę połączyć się z serwerem https tylko w celach testowych. (Klient nie może udostępnić jednej z pasujących nazw FQDN ani testować na http). Czy istnieje sposób rozwiązania tego problemu podczas korzystania z WebView? Czy po prostu upuszczam ten kod w działaniu, w którym znajduje się WebView i „po prostu działa”? (Podejrzewam, że nie… ??)
Joe D'Andrea
Próbuję użyć tego rozwiązania krok po kroku i otrzymuję taki wyjątek: 07-25 12: 35: 25.941: WARN / System.err (24383): java.lang.ClassCastException: org.apache.harmony.luni .internal.net.www.protocol.http.HttpURLConnectionImpl w miejscu, w którym próbuję otworzyć połączenie ... jakiś pomysł, dlaczego?
Robert,
1
Hej, zrobiłem tak, jak zasugerowałeś, ale otrzymuję wyjątek jako javax.net.ssl.SSLException: Received fatal alert: bad_record_mac. Próbowałem również zastąpienie TLSz SSLale to nie pomogło. Proszę, pomóż mi, dzięki
devsri,
40
Chociaż jest to dobre w fazie rozwoju, powinieneś być świadomy faktu, że umożliwia to każdemu MITM twoje bezpieczne połączenie poprzez sfałszowanie losowego certyfikatu SSL, co sprawia, że twoje połączenie nie jest już bezpieczne. Rzucić okiem na to pytanie , aby zobaczyć, że podjął właściwą drogę tutaj , aby zobaczyć w jaki sposób, aby otrzymać certyfikat, a wreszcie to , aby dowiedzieć się, jak dodać go do magazynu kluczy.
cimnine
2
Nie należy używać polecania ani publikować tego kodu. To jest radykalnie niepewne. Powinieneś rozwiązać rzeczywisty problem.
Markiz Lorne
33
Próbując odpowiedzieć na to pytanie, znalazłem lepszy tutorial. Dzięki niemu nie musisz narażać się na sprawdzanie certyfikatu.
To jest doskonała odpowiedź. Napisałem aktualizację, która pokazuje, jak radzić sobie z nie wymienionymi urzędami certyfikacji, gdy otrzymywałem błąd PeerCertificate. Zobacz to tutaj: blog.donnfelker.com/2011/06/13/…
Donn Felker
6
Możesz również spojrzeć na mój artykuł na blogu, bardzo podobny do crazybobs.
To rozwiązanie nie zagraża również sprawdzaniu certyfikatów i wyjaśnia, jak dodać zaufane certyfikaty do własnego magazynu kluczy.
Podczas tworzenia aplikacji korzystającej z protokołu https serwer testowy nie ma ważnego certyfikatu SSL. Czasami witryna internetowa korzysta z certyfikatu z podpisem własnym lub korzysta z bezpłatnego certyfikatu SSL. Więc jeśli spróbujesz połączyć się z serwerem za pomocą Apache HttpClient, pojawi się wyjątek informujący, że „peer nie uwierzytelniony”. Chociaż ufanie wszystkim certyfikatom oprogramowania produkcyjnego nie jest dobrą praktyką, może być to konieczne w zależności od sytuacji. To rozwiązanie rozwiązuje wyjątek spowodowany przez „nieuwierzytelniony element równorzędny”.
Zanim jednak przejdziemy do rozwiązania, muszę Cię ostrzec, że nie jest to dobry pomysł na aplikację produkcyjną. Naruszy to cel używania certyfikatu bezpieczeństwa. Więc jeśli nie masz dobrego powodu lub jesteś pewien, że nie spowoduje to żadnego problemu, nie korzystaj z tego rozwiązania.
Zwykle tworzysz coś HttpClienttakiego.
HttpClient httpclient = new DefaultHttpClient();
Ale musisz zmienić sposób tworzenia HttpClient.
Najpierw musisz utworzyć rozszerzającą klasę org.apache.http.conn.ssl.SSLSocketFactory.
Jeśli próbujesz wysłać prośbę o wpis na stronę logowania, reszta kodu będzie wyglądać tak.
private URI url =new URI("url of the action of the form");HttpPost httppost =newHttpPost(url);List<NameValuePair> nameValuePairs =newArrayList<NameValuePair>();
nameValuePairs.add(newBasicNameValuePair("username","user"));
nameValuePairs.add(newBasicNameValuePair("password","password"));try{
httppost.setEntity(newUrlEncodedFormEntity(nameValuePairs));HttpResponse response = httpclient.execute(httppost);HttpEntity entity = response.getEntity();InputStream is = entity.getContent();}catch(UnsupportedEncodingException e){// TODO Auto-generated catch block
e.printStackTrace();}catch(ClientProtocolException e){// TODO Auto-generated catch block
e.printStackTrace();}catch(IOException e){// TODO Auto-generated catch block
e.printStackTrace();}
Otrzymasz stronę HTML do InputStream. Następnie możesz zrobić, co chcesz, ze zwróconą stroną HTML.
Ale tutaj napotkasz problem. Jeżeli będziesz chciał zarządzać sesją za pomocą plików cookies, nie będziesz mógł tego zrobić tą metodą. Jeśli chcesz otrzymywać pliki cookie, musisz to zrobić za pośrednictwem przeglądarki. Tylko wtedy otrzymasz ciasteczka.
Jeśli używasz certyfikatu StartSSL lub Thawte, nie powiedzie się to w przypadku Froyo i starszych wersji. Możesz użyć repozytorium CAcert nowszej wersji zamiast ufać każdemu certyfikatowi.
Tak jak powiedziałem, nie znam specyfiki Androida, ale nadszedł dzień, w którym musisz powiedzieć platformie, jaki jest certyfikat SSL serwera, z którym się łączysz. Dzieje się tak, jeśli używasz certyfikatu z podpisem własnym, który nie jest rozpoznawany przez platformę. Klasa SslCertificate prawdopodobnie będzie pomocna: developer.android.com/reference/android/net/http/ ... Zagłębię się w to później dzisiaj, kiedy będę miał więcej czasu.
Matti Lyra
1
Jest to znany problem występujący w systemie Android 2.x. Zmagałem się z tym problemem przez tydzień, aż natrafiłem na następujące pytanie, które nie tylko daje dobre tło problemu, ale także zapewnia działające i skuteczne rozwiązanie pozbawione jakichkolwiek luk w zabezpieczeniach.
Z jakiegoś powodu rozwiązanie wspomniane powyżej dla httpClient nie zadziałało. Na koniec udało mi się sprawić, że to zadziała, poprawnie nadpisując metodę podczas implementacji niestandardowej klasy SSLSocketFactory.
CertificadoAceptar ca =newCertificadoAceptar();
ca.allowAllSSL();HttpsTransportSETransport=newHttpsTransportSE("iphost or host name",8080,"/WS/wsexample.asmx?WSDL",30000);
Źródła, które pomogły mi w pracy z własnym certyfikatem z podpisem własnym na moim serwerze AWS Apache i łączeniu się z HttpsURLConnection z urządzenia z systemem Android:
Upewnij się, że serwer obsługuje protokół https (sudo yum install -y mod24_ssl)
Umieść ten skrypt w pliku create_my_certs.sh:
#!/bin/bash
FQDN=$1
# make directories to work from
mkdir -p server/ client/ all/#Create your very own RootCertificateAuthority
openssl genrsa \
-out all/my-private-root-ca.privkey.pem \
2048#Self-sign your RootCertificateAuthority#Sincethis is private, the details can be as bogus as you like
openssl req \
-x509 \
-new \
-nodes \
-key all/my-private-root-ca.privkey.pem \
-days 1024 \
-out all/my-private-root-ca.cert.pem \
-subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com"#Create a DeviceCertificatefor each domain,# such as example.com,*.example.com, awesome.example.com
# NOTE:You MUST match CN to the domain name or ip address you want to use
openssl genrsa \
-out all/privkey.pem \
2048#Create a request from your Device, which your Root CA will sign
openssl req -new \
-key all/privkey.pem \
-out all/csr.pem \
-subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}"#Sign the request from Device with your Root CA
openssl x509 \
-req -in all/csr.pem \
-CA all/my-private-root-ca.cert.pem \
-CAkey all/my-private-root-ca.privkey.pem \
-CAcreateserial \
-out all/cert.pem \
-days 500#Put things in their proper place
rsync -a all/{privkey,cert}.pem server/
cat all/cert.pem > server/fullchain.pem # we have no intermediates in thiscase
rsync -a all/my-private-root-ca.cert.pem server/
rsync -a all/my-private-root-ca.cert.pem client/
Biegać bash create_my_certs.sh yourdomain.com
Umieść certyfikaty w odpowiednich miejscach na serwerze (konfigurację znajdziesz w /etc/httpd/conf.d/ssl.conf). Wszystko to należy ustawić:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Uruchom ponownie httpd za pomocą sudo service httpd restarti upewnij się, że httpd rozpoczęte:
Zatrzymywanie httpd: [OK]
Uruchamianie httpd: [OK]
Skopiuj my-private-root-ca.certdo folderu zasobów projektu systemu Android
// Create a KeyStore containing our trusted CAsString keyStoreType =KeyStore.getDefaultType();KeyStore keyStore =KeyStore.getInstance(keyStoreType);
keyStore.load(null,null);
keyStore.setCertificateEntry("ca", ca);// Create a TrustManager that trusts the CAs in our KeyStoreString tmfAlgorithm =TrustManagerFactory.getDefaultAlgorithm();TrustManagerFactory tmf =TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);// Create an SSLContext that uses our TrustManagerSSLContext=SSLContext.getInstance("TLS");SSSLContext.init(null, tmf.getTrustManagers(),null);
I nawiąż połączenie za pomocą HttpsURLConnection:
Połączenie HttpsURLConnection = (HttpsURLConnection) url.openConnection (); connection.setSSLSocketFactory (SSLContext.getSocketFactory ());
Odpowiedzi:
Zgaduję, ale jeśli chcesz, aby rzeczywiście nastąpił uścisk dłoni, musisz powiadomić Androida o swoim certyfikacie. Jeśli chcesz zaakceptować bez względu na wszystko, użyj tego pseudokodu, aby uzyskać to, czego potrzebujesz z klientem Apache HTTP:
CustomSSLSocketFactory:
FullX509TrustManager to klasa, która implementuje javax.net.ssl.X509TrustManager, ale żadna z metod nie wykonuje żadnej pracy, pobierz próbkę tutaj .
Powodzenia!
źródło
FullX509TrustManager
To właśnie robię. Po prostu nie sprawdza już certyfikatu.
i
źródło
javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
. Próbowałem również zastąpienieTLS
zSSL
ale to nie pomogło. Proszę, pomóż mi, dziękiPróbując odpowiedzieć na to pytanie, znalazłem lepszy tutorial. Dzięki niemu nie musisz narażać się na sprawdzanie certyfikatu.
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
* Nie napisałem tego, ale dzięki Bobowi Lee za pracę
źródło
Możesz również spojrzeć na mój artykuł na blogu, bardzo podobny do crazybobs.
To rozwiązanie nie zagraża również sprawdzaniu certyfikatów i wyjaśnia, jak dodać zaufane certyfikaty do własnego magazynu kluczy.
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
źródło
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
Dzięki uprzejmości Maduranga
Podczas tworzenia aplikacji korzystającej z protokołu https serwer testowy nie ma ważnego certyfikatu SSL. Czasami witryna internetowa korzysta z certyfikatu z podpisem własnym lub korzysta z bezpłatnego certyfikatu SSL. Więc jeśli spróbujesz połączyć się z serwerem za pomocą Apache
HttpClient
, pojawi się wyjątek informujący, że „peer nie uwierzytelniony”. Chociaż ufanie wszystkim certyfikatom oprogramowania produkcyjnego nie jest dobrą praktyką, może być to konieczne w zależności od sytuacji. To rozwiązanie rozwiązuje wyjątek spowodowany przez „nieuwierzytelniony element równorzędny”.Zanim jednak przejdziemy do rozwiązania, muszę Cię ostrzec, że nie jest to dobry pomysł na aplikację produkcyjną. Naruszy to cel używania certyfikatu bezpieczeństwa. Więc jeśli nie masz dobrego powodu lub jesteś pewien, że nie spowoduje to żadnego problemu, nie korzystaj z tego rozwiązania.
Zwykle tworzysz coś
HttpClient
takiego.HttpClient httpclient = new DefaultHttpClient();
Ale musisz zmienić sposób tworzenia HttpClient.
Najpierw musisz utworzyć rozszerzającą klasę
org.apache.http.conn.ssl.SSLSocketFactory
.Następnie utwórz taką metodę.
Następnie możesz utworzyć plik
HttpClient
.HttpClient httpclient = getNewHttpClient();
Jeśli próbujesz wysłać prośbę o wpis na stronę logowania, reszta kodu będzie wyglądać tak.
Otrzymasz stronę HTML do InputStream. Następnie możesz zrobić, co chcesz, ze zwróconą stroną HTML.
Ale tutaj napotkasz problem. Jeżeli będziesz chciał zarządzać sesją za pomocą plików cookies, nie będziesz mógł tego zrobić tą metodą. Jeśli chcesz otrzymywać pliki cookie, musisz to zrobić za pośrednictwem przeglądarki. Tylko wtedy otrzymasz ciasteczka.
źródło
Jeśli używasz certyfikatu StartSSL lub Thawte, nie powiedzie się to w przypadku Froyo i starszych wersji. Możesz użyć repozytorium CAcert nowszej wersji zamiast ufać każdemu certyfikatowi.
źródło
Żaden z nich nie działał dla mnie (dodatkowo pogarszany przez błąd Thawte ). W końcu udało mi się to naprawić dzięki akceptacji SSL z podpisem własnym na Androidzie, a obsługa niestandardowego SSL przestała działać na Androidzie 2.2 FroYo
źródło
Żadna z tych odpowiedzi nie zadziałała dla mnie, więc oto kod, który ufa jakimkolwiek certyfikatom.
źródło
Nie wiem, jakie są specyfikacje Androida dotyczące certyfikatów ssl, ale miałoby sens, gdyby Android nie akceptował samodzielnie podpisanego certyfikatu ssl. Znalazłem ten post na forach Androida, który wydaje się dotyczyć tego samego problemu: http://androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html
źródło
Jest to znany problem występujący w systemie Android 2.x. Zmagałem się z tym problemem przez tydzień, aż natrafiłem na następujące pytanie, które nie tylko daje dobre tło problemu, ale także zapewnia działające i skuteczne rozwiązanie pozbawione jakichkolwiek luk w zabezpieczeniach.
Błąd „Brak certyfikatu równorzędnego” w systemie Android 2.3, ale NIE w wersji 4
źródło
Z jakiegoś powodu rozwiązanie wspomniane powyżej dla httpClient nie zadziałało. Na koniec udało mi się sprawić, że to zadziała, poprawnie nadpisując metodę podczas implementacji niestandardowej klasy SSLSocketFactory.
Tak to działało idealnie dla mnie. Możesz zobaczyć pełną klasę niestandardową i implementację w następującym wątku: http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
źródło
Zrobiłem tę klasę i znalazłem
w tobie kod biały to
źródło
Źródła, które pomogły mi w pracy z własnym certyfikatem z podpisem własnym na moim serwerze AWS Apache i łączeniu się z HttpsURLConnection z urządzenia z systemem Android:
SSL na instancji AWS - samouczek Amazon na temat
SSL Android Security z HTTPS i SSL - tworzenie własnego menedżera zaufania na kliencie do akceptowania twój certyfikat
Tworzenie certyfikatu z podpisem własnym - łatwy skrypt do tworzenia certyfikatów
Następnie wykonałem następujące czynności:
create_my_certs.sh
:bash create_my_certs.sh yourdomain.com
Umieść certyfikaty w odpowiednich miejscach na serwerze (konfigurację znajdziesz w /etc/httpd/conf.d/ssl.conf). Wszystko to należy ustawić:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Uruchom ponownie httpd za pomocą
sudo service httpd restart
i upewnij się, że httpd rozpoczęte:Zatrzymywanie httpd: [OK]
Uruchamianie httpd: [OK]
Skopiuj
my-private-root-ca.cert
do folderu zasobów projektu systemu AndroidUtwórz swojego menedżera zaufania:
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance ("X.509"); InputStream caInput = context.getAssets (). Open ("my-private-root-ca.cert.pem"); Certyfikat ca; try {ca = cf.generateCertificate (caInput); } wreszcie {caInput.close (); }
I nawiąż połączenie za pomocą HttpsURLConnection:
Połączenie HttpsURLConnection = (HttpsURLConnection) url.openConnection (); connection.setSSLSocketFactory (SSLContext.getSocketFactory ());
To wszystko, wypróbuj połączenie https.
źródło
Prawdopodobnie możesz spróbować czegoś takiego. To mi pomogło
źródło
Po prostu użyj tej metody jako swojego HTTPClient:
źródło