https连接Android

我正在做一个HTTPS后,我得到一个例外的SSL例外不受信任的服务器证书。 如果我做正常的http,它工作得很好。 我必须以某种方式接受服务器证书吗?

我正在猜测,但是如果你想要一个真正的握手发生,你必须让android知道你的证书。 如果你只想接受,不pipe用什么,然后用这个伪代码来得到你所需要的Apache HTTP Client:

SchemeRegistry schemeRegistry = new SchemeRegistry (); schemeRegistry.register (new Scheme ("http", PlainSocketFactory.getSocketFactory (), 80)); schemeRegistry.register (new Scheme ("https", new CustomSSLSocketFactory (), 443)); ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager ( params, schemeRegistry); return new DefaultHttpClient (cm, params); 

CustomSSLSocketFactory:

 public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory { private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory (); public CustomSSLSocketFactory () { super(null); try { SSLContext context = SSLContext.getInstance ("TLS"); TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () }; context.init (null, tm, new SecureRandom ()); FACTORY = context.getSocketFactory (); } catch (Exception e) { e.printStackTrace(); } } public Socket createSocket() throws IOException { 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的类,但是其中没有一个方法实际执行任何工作, 在这里得到一个示例。

祝你好运!

这就是我正在做的。 它根本不检查证书了。

 // always verify the host - dont check for certificate final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; /** * Trust every server - dont check for any certificate */ private static void trustAllHosts() { // Create a trust manager that does not validate certificate chains 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 { } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection .setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } 

  HttpURLConnection http = null; if (url.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); https.setHostnameVerifier(DO_NOT_VERIFY); http = https; } else { http = (HttpURLConnection) url.openConnection(); } 

在试图回答这个问题时,我发现了一个更好的教程。 有了它,你不必妥协的证书检查。

http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

*我没有写这个,但是感谢Bob Lee的工作

你也可以看看我的博客文章,非常类似crazybobs。

此解决scheme也不会影响证书检查,并解释如何将可信证书添加到您自己的密钥库中。

http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/

http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html

礼貌马杜兰

在开发使用https的应用程序时,testing服务器没有有效的SSL证书。 或者有时网站使用自签名证书,或者网站使用免费SSL证书。 所以如果你尝试使用Apache HttpClient连接到服务器,你会得到一个exception,告诉“peer not authenticated”。 虽然信任生产软件中的所有证书并不是一个好习惯,但您可能需要根据具体情况进行操作。 该解决scheme解决了由“未通过身份validation”造成的exception。

但在我们解决问题之前,我必须警告你,这不是一个生产应用的好主意。 这将违反使用安全证书的目的。 所以,除非你有充分的理由,或者你确定这不会造成任何问题,否则不要使用这个解决scheme。

通常你像这样创build一个HttpClient

HttpClient httpclient = new DefaultHttpClient();

但是你必须改变你创buildHttpClient的方式。

首先你必须创build一个扩展org.apache.http.conn.ssl.SSLSocketFactory的类。

 import org.apache.http.conn.ssl.SSLSocketFactory; 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; 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(); } } 

然后创build一个像这样的方法。

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

然后你可以创buildHttpClient

HttpClient httpclient = getNewHttpClient();

如果您正在尝试向login页面发送发布请求,则其余代码将如下所示。

 private URI url = new URI("url of the action of the form"); HttpPost httppost = new HttpPost(url); List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(); nameValuePairs.add(new BasicNameValuePair("username", "user")); nameValuePairs.add(new BasicNameValuePair("password", "password")); try { httppost.setEntity(new UrlEncodedFormEntity(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(); } 

你得到了inputstream的html页面。 然后,你可以做任何你想要的与返回的HTML页面。

但是在这里你将面临一个问题。 如果您想使用cookiepipe理会话,则无法使用此方法执行此操作。 如果你想获得cookie,你必须通过浏览器来完成。 那么只有你会收到cookies。

如果您使用的是StartSSL或Thawte证书,则Froyo和旧版本将会失败。 您可以使用较新版本的CAcert存储库,而不是信任每个证书。

这些都没有为我工作(由Thawte臭虫也加剧)。 最终,我通过Android上的自签名SSL接受和自定义SSL处理在Android 2.2 FroYo上停止了工作

任何这个答案都不适合我,所以这里是信任任何证书的代码。

 import java.io.IOException; import java.net.Socket; import java.security.KeyManagementException; 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.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; 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.conn.ssl.X509HostnameVerifier; 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.HttpConnectionParams; import org.apache.http.params.HttpParams; public class HttpsClientBuilder { public static DefaultHttpClient getBelieverHttpsClient() { DefaultHttpClient client = null; SchemeRegistry Current_Scheme = new SchemeRegistry(); Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); try { Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443)); } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnrecoverableKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } HttpParams Current_Params = new BasicHttpParams(); int timeoutConnection = 8000; HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection); int timeoutSocket = 10000; HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket); ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme); client = new DefaultHttpClient(Current_Manager, Current_Params); //HttpPost httpPost = new HttpPost(url); //client.execute(httpPost); return client; } public static class Naive_SSLSocketFactory extends SSLSocketFactory { protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS"); public Naive_SSLSocketFactory () throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(null, null, null, null, null, (X509HostnameVerifier)null); Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { return Cur_SSL_Context.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return Cur_SSL_Context.getSocketFactory().createSocket(); } } private static class X509_Trust_Manager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub } public X509Certificate[] getAcceptedIssuers() { // TODO Auto-generated method stub return null; } }; } 

我不知道关于ssl证书的Android细节,但是Android不会接受一个自签名的ssl证书。 我发现这个post从Android论坛似乎是解决同一问题: http : //androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html

这是Android 2.x的一个已知问题。 我一直在为这个问题苦苦挣扎了一个星期,直到遇到以下问题,这不仅给出了问题的良好背景,而且提供了一个没有任何安全漏洞的工作和有效的解决scheme。

Android 2.3中没有“同行证书”错误,但不是4

由于某种原因,上面提到的httpClient解决scheme并不适合我。 最后我能够通过在实现自定义SSLSocketFactory类时正确地重写该方法来使其工作。

 @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslFactory.createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslFactory.createSocket(); } 

这对我来说是完美的。 您可以看到完整的自定义类并在以下线程上实现: http : //blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/

我做这个class,find了

 package com.example.fakessl; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import android.util.Log; public class CertificadoAceptar { private static TrustManager[] trustManagers; public static class _FakeX509TrustManager implements javax.net.ssl.X509TrustManager { private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {}; public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } public boolean isClientTrusted(X509Certificate[] chain) { return (true); } public boolean isServerTrusted(X509Certificate[] chain) { return (true); } public X509Certificate[] getAcceptedIssuers() { return (_AcceptedIssuers); } } public static void allowAllSSL() { javax.net.ssl.HttpsURLConnection .setDefaultHostnameVerifier(new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }); javax.net.ssl.SSLContext context = null; if (trustManagers == null) { trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() }; } try { context = javax.net.ssl.SSLContext.getInstance("TLS"); context.init(null, trustManagers, new SecureRandom()); } catch (NoSuchAlgorithmException e) { Log.e("allowAllSSL", e.toString()); } catch (KeyManagementException e) { Log.e("allowAllSSL", e.toString()); } javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context .getSocketFactory()); } } 

在你的代码中白色这个

 CertificadoAceptar ca = new CertificadoAceptar(); ca.allowAllSSL(); HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000); 

有助于我使用我的AWS Apache服务器上的自签名证书并使用Android设备的HttpsURLConnection进行连接的源代码:

aws实例上的SSL – 有关ssl的amazon教程
使用HTTPS和SSL的Android安全性 – 在客户端上创build您自己的信任pipe理器以接受您的证书
创build自签名证书 – 用于创build证书的简单脚本

然后我做了以下几点:

  1. 确保服务器支持https(sudo yum install -y mod24_ssl)
  2. 把这个脚本放在一个文件create_my_certs.sh
 #!/bin/bash FQDN=$1 # make directories to work from mkdir -p server/ client/ all/ # Create your very own Root Certificate Authority openssl genrsa \ -out all/my-private-root-ca.privkey.pem \ 2048 # Self-sign your Root Certificate Authority # Since this 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 Device Certificate for 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 this case rsync -a all/my-private-root-ca.cert.pem server/ rsync -a all/my-private-root-ca.cert.pem client/ 
  1. 运行bash create_my_certs.sh yourdomain.com
  2. 将证书放在服务器上的适当位置(可以在/etc/httpd/conf.d/ssl.conf中findconfiguration)。 所有这些都应该设置:
    了SSLCertificateFile
    了SSLCertificateKeyFile
    SSLCertificateChainFile
    SSLCACertificateFile

  3. 使用sudo service httpd restart重新启动httpd并确保httpd已启动:
    停止httpd:[确定]
    启动httpd:[确定]

  4. 复制my-private-root-ca.cert到你的android项目资产文件夹

  5. 创build您的信任pipe理器:

    SSLContext SSLContext;

    CertificateFactory cf = CertificateFactory.getInstance(“X.509”); InputStream caInput = context.getAssets()。open(“my-private-root-ca.cert.pem”); 证书ca; 尝试{ca = cf.generateCertificate(caInput); } finally {caInput.close(); }

      // Create a KeyStore containing our trusted CAs String 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 KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore); // Create an SSLContext that uses our TrustManager SSLContext = SSLContext.getInstance("TLS"); SSSLContext.init(null, tmf.getTrustManagers(), null); 
  6. 并使用HttpsURLConnection进行连接:

    HttpsURLConnection连接=(HttpsURLConnection)url.openConnection(); connection.setSSLSocketFactory(SSLContext.getSocketFactory());

  7. 就是这样,试试你的https连接。

只要使用这个方法作为你的HTTPClient:

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