Я делаю сообщение https и получаю исключение из-за исключения ssl. Сертификат недоверенного сервера. Если я делаю обычный http, он работает отлично. Нужно ли мне как-то принимать сертификат сервера?
Я делаю предположение, но если вы хотите, чтобы произошло фактическое рукопожатие, вы должны сообщить Android о вашем сертификате. Если вы хотите просто принять что-либо, используйте этот псевдокод, чтобы получить то, что вам нужно, с помощью HTTP-клиента Apache:
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 - это класс, реализующий javax.net.ssl.X509TrustManager, но ни один из методов на самом деле не выполняет никакой работы, см. Образец здесь .
return FACTORY.createSocket (); возникла проблема. Созданный сокет выдает исключение нулевого указателя при выполнении (). Также я заметил, что есть 2 класса SocketFactory. 1. org.apache.http.conn.ssl.SSLSocketFactory и 2. javax.net.ssl.SSLSocketFactory
Codevalley
2
Привет, Нейт, это похоже на кое-что полезное в моей ситуации. Но у меня возникли проблемы с созданием CustomSSLSocketFactory. Какой класс предполагается расширить? Или какой интерфейс предполагается реализовать? Я экспериментировал с: javax.net.SocketFactory, javax.net.ssl.SSLSocketFactory, org.apache.http.conn.scheme.SocketFactory, все из которых заставляют реализацию других методов ... Итак, в общем, что пространства имен классов используются в вашем коде? Спасибо. :)
Cephron
2
У меня не работает, выдает такую же ошибку сертификата Недоверенного сервера.
Омар Рехман
1
как я могу получить этот классFullX509TrustManager
RajaReddy PolamReddy
89
Вот что я делаю. Он просто больше не проверяет сертификат.
// 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();}}
Выглядит хорошо! Однако я использую WebView, и мне нужно подключиться к https-серверу только в тестовых целях. (Клиент не может предоставить ему соответствующее полное доменное имя, и они не могут протестировать его по http.) Есть ли способ решить эту проблему при использовании WebView? Могу ли я просто поместить этот код в Activity, где находится WebView, и «он просто работает»? (Не подозревая… ??)
Джо Д'Андреа
Я пытаюсь использовать это решение шаг за шагом, и я получаю такое исключение: 07-25 12: 35: 25.941: WARN / System.err (24383): java.lang.ClassCastException: org.apache.harmony.luni .internal.net.www.protocol.http.HttpURLConnectionImpl на месте, где я пытаюсь открыть соединение ... любая идея, почему ??
Роберт
1
Эй, я сделал, как вы предложили, но я получаю исключение javax.net.ssl.SSLException: Received fatal alert: bad_record_mac. Я также попытался заменить TLSс , SSLно это не помогло. Пожалуйста, помогите мне, спасибо
devsri
40
Хотя это хорошо на этапе разработки, вы должны знать о том, что это позволяет любому MITM ваше безопасное соединение, подделав случайный сертификат SSL, что делает ваше соединение более небезопасным. Посмотрите на этот вопрос, чтобы убедиться, что все сделано правильно, здесь, чтобы увидеть, как получить сертификат, и, наконец, на это, чтобы узнать, как добавить его в хранилище ключей.
cimnine 01
2
Вы не должны использовать рекомендовать или публиковать этот код. Это в корне небезопасно. Вы должны решить настоящую проблему.
Marquis of Lorne
33
Пытаясь ответить на этот вопрос, я нашел лучшее руководство. С его помощью вам не придется скомпрометировать проверку сертификата.
Это идеальный ответ. Я сделал сообщение об обновлении, в котором показано, как бороться с не указанными в списке центрами сертификации, поскольку я получал ошибку PeerCertificate. Смотрите здесь: blog.donnfelker.com/2011/06/13/…
Донн Фелкер,
6
Вы также можете посмотреть мою статью в блоге, очень похожую на crazybobs.
Это решение также не ставит под угрозу проверку сертификатов и объясняет, как добавить доверенные сертификаты в ваше собственное хранилище ключей.
При разработке приложения, использующего https, на вашем тестовом сервере нет действующего сертификата SSL. Или иногда веб-сайт использует самозаверяющий сертификат или веб-сайт использует бесплатный сертификат SSL. Итак, если вы попытаетесь подключиться к серверу с помощью ApacheHttpClient , вы получите исключение, сообщающее, что «одноранговый узел не аутентифицирован». Хотя доверять всем сертификатам в производственном программном обеспечении не рекомендуется, возможно, вам придется сделать это в зависимости от ситуации. Это решение устраняет исключение, вызванное «одноранговый узел не аутентифицирован».
Но прежде чем мы перейдем к решению, я должен вас предупредить, что это не лучшая идея для производственного приложения. Это нарушит цель использования сертификата безопасности. Поэтому, если у вас нет веской причины или если вы уверены, что это не вызовет никаких проблем, не используйте это решение.
Обычно вы создаете HttpClientтакой.
HttpClient httpclient = new DefaultHttpClient();
Но вам нужно изменить способ создания HttpClient.
Сначала вам нужно создать класс, расширяющийся org.apache.http.conn.ssl.SSLSocketFactory.
Если вы пытаетесь отправить почтовый запрос на страницу входа, остальной код будет таким.
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();}
Вы получаете html-страницу в InputStream. Затем вы можете делать все, что захотите, с возвращенной html-страницей.
Но здесь вы столкнетесь с проблемой. Если вы хотите управлять сеансом с помощью файлов cookie, вы не сможете сделать это с помощью этого метода. Если вы хотите получить файлы cookie, вам нужно будет сделать это через браузер. Только тогда вы получите куки.
Если вы используете сертификат StartSSL или Thawte, он не будет работать для Froyo и более старых версий. Вы можете использовать репозиторий CAcert новой версии вместо того, чтобы доверять каждому сертификату.
Как я уже сказал, я не знаю специфики Android, но я считаю, что вы должны сообщить платформе, что такое ssl-сертификат сервера, к которому вы подключаетесь. Это если вы используете самоподписанный сертификат, который не распознается платформой. Класс SslCertificate, вероятно, будет вам полезен: developer.android.com/reference/android/net/http/ ... Я углублюсь в это сегодня позже, когда у меня будет больше времени.
Matti Lyra,
1
Это известная проблема Android 2.x. Я боролся с этой проблемой в течение недели, пока не наткнулся на следующий вопрос, который не только дает хорошее представление о проблеме, но также обеспечивает рабочее и эффективное решение, лишенное каких-либо дыр в безопасности.
По какой-то причине решение, упомянутое выше для httpClient, у меня не сработало. В конце концов я смог заставить его работать, правильно переопределив метод при реализации настраиваемого класса SSLSocketFactory.
CertificadoAceptar ca =newCertificadoAceptar();
ca.allowAllSSL();HttpsTransportSETransport=newHttpsTransportSE("iphost or host name",8080,"/WS/wsexample.asmx?WSDL",30000);
Источники, которые помогли мне приступить к работе с моим самоподписанным сертификатом на моем сервере AWS Apache и подключиться к HttpsURLConnection с устройства Android:
Убедитесь, что сервер поддерживает https (sudo yum install -y mod24_ssl)
Поместите этот скрипт в файл 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/
Бегать bash create_my_certs.sh yourdomain.com
Поместите сертификаты в нужное место на сервере (вы можете найти конфигурацию в /etc/httpd/conf.d/ssl.conf). Все они должны быть установлены:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Перезапустите httpd с помощью sudo service httpd restartи убедитесь, что httpd запущен:
Остановка httpd: [OK]
Запуск httpd: [OK]
Скопируйте my-private-root-ca.certв папку с ресурсами вашего проекта 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);
И сделаем соединение с помощью HttpsURLConnection:
Ответы:
Я делаю предположение, но если вы хотите, чтобы произошло фактическое рукопожатие, вы должны сообщить Android о вашем сертификате. Если вы хотите просто принять что-либо, используйте этот псевдокод, чтобы получить то, что вам нужно, с помощью HTTP-клиента Apache:
CustomSSLSocketFactory:
FullX509TrustManager - это класс, реализующий javax.net.ssl.X509TrustManager, но ни один из методов на самом деле не выполняет никакой работы, см. Образец здесь .
Удачи!
источник
FullX509TrustManager
Вот что я делаю. Он просто больше не проверяет сертификат.
и
источник
javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
. Я также попытался заменитьTLS
с ,SSL
но это не помогло. Пожалуйста, помогите мне, спасибоПытаясь ответить на этот вопрос, я нашел лучшее руководство. С его помощью вам не придется скомпрометировать проверку сертификата.
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
* Я не писал это, но спасибо Бобу Ли за работу
источник
Вы также можете посмотреть мою статью в блоге, очень похожую на crazybobs.
Это решение также не ставит под угрозу проверку сертификатов и объясняет, как добавить доверенные сертификаты в ваше собственное хранилище ключей.
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
источник
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
Предоставлено Мадуранга
При разработке приложения, использующего https, на вашем тестовом сервере нет действующего сертификата SSL. Или иногда веб-сайт использует самозаверяющий сертификат или веб-сайт использует бесплатный сертификат SSL. Итак, если вы попытаетесь подключиться к серверу с помощью Apache
HttpClient
, вы получите исключение, сообщающее, что «одноранговый узел не аутентифицирован». Хотя доверять всем сертификатам в производственном программном обеспечении не рекомендуется, возможно, вам придется сделать это в зависимости от ситуации. Это решение устраняет исключение, вызванное «одноранговый узел не аутентифицирован».Но прежде чем мы перейдем к решению, я должен вас предупредить, что это не лучшая идея для производственного приложения. Это нарушит цель использования сертификата безопасности. Поэтому, если у вас нет веской причины или если вы уверены, что это не вызовет никаких проблем, не используйте это решение.
Обычно вы создаете
HttpClient
такой.HttpClient httpclient = new DefaultHttpClient();
Но вам нужно изменить способ создания HttpClient.
Сначала вам нужно создать класс, расширяющийся
org.apache.http.conn.ssl.SSLSocketFactory
.Затем создайте такой метод.
Затем вы можете создать файл
HttpClient
.HttpClient httpclient = getNewHttpClient();
Если вы пытаетесь отправить почтовый запрос на страницу входа, остальной код будет таким.
Вы получаете html-страницу в InputStream. Затем вы можете делать все, что захотите, с возвращенной html-страницей.
Но здесь вы столкнетесь с проблемой. Если вы хотите управлять сеансом с помощью файлов cookie, вы не сможете сделать это с помощью этого метода. Если вы хотите получить файлы cookie, вам нужно будет сделать это через браузер. Только тогда вы получите куки.
источник
Если вы используете сертификат StartSSL или Thawte, он не будет работать для Froyo и более старых версий. Вы можете использовать репозиторий CAcert новой версии вместо того, чтобы доверять каждому сертификату.
источник
Ни один из них не помог мне (усугубляется ошибкой Thawte ). В конце концов я исправил это с принятием самоподписанного SSL на Android, а обработка пользовательского SSL перестала работать на Android 2.2 FroYo
источник
Ни один из этих ответов не сработал для меня, поэтому вот код, который доверяет любым сертификатам.
источник
Я не знаю особенностей Android для ssl-сертификатов, но было бы логично, что Android сразу же не примет самоподписанный ssl-сертификат. Я нашел этот пост на форумах Android, который, похоже, посвящен той же проблеме: http://androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html
источник
Это известная проблема Android 2.x. Я боролся с этой проблемой в течение недели, пока не наткнулся на следующий вопрос, который не только дает хорошее представление о проблеме, но также обеспечивает рабочее и эффективное решение, лишенное каких-либо дыр в безопасности.
Ошибка "Нет однорангового сертификата" в Android 2.3, но НЕ в 4
источник
По какой-то причине решение, упомянутое выше для httpClient, у меня не сработало. В конце концов я смог заставить его работать, правильно переопределив метод при реализации настраиваемого класса SSLSocketFactory.
Вот как это отлично сработало для меня. Вы можете увидеть полный пользовательский класс и его реализацию в следующем потоке: http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
источник
Я сделал этот класс и нашел
в вашем коде белый это
источник
Источники, которые помогли мне приступить к работе с моим самоподписанным сертификатом на моем сервере AWS Apache и подключиться к HttpsURLConnection с устройства Android:
SSL на экземпляре aws - учебник amazon по ssl
Безопасность Android с HTTPS и SSL - создание собственного диспетчера доверия на клиенте для принятия ваш сертификат
Создание самоподписанного сертификата - простой скрипт для создания ваших сертификатов
Затем я сделал следующее:
create_my_certs.sh
:bash create_my_certs.sh yourdomain.com
Поместите сертификаты в нужное место на сервере (вы можете найти конфигурацию в /etc/httpd/conf.d/ssl.conf). Все они должны быть установлены:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Перезапустите httpd с помощью
sudo service httpd restart
и убедитесь, что httpd запущен:Остановка httpd: [OK]
Запуск httpd: [OK]
Скопируйте
my-private-root-ca.cert
в папку с ресурсами вашего проекта AndroidСоздайте своего доверительного менеджера:
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance ("X.509"); InputStream caInput = context.getAssets (). Open ("мой-частный-корень-ca.cert.pem"); Сертификат ca; попробуйте {ca = cf.generateCertificate (caInput); } наконец {caInput.close (); }
И сделаем соединение с помощью HttpsURLConnection:
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection (); connection.setSSLSocketFactory (SSLContext.getSocketFactory ());
Вот и все, попробуйте https-соединение.
источник
Наверное, можно попробовать что-нибудь подобное. Это помогло мне
источник
Просто используйте этот метод как свой HTTPClient:
источник