DefaultHttpClient, Certificates, Https and posting

2019-03-17 01:05发布

问题:

My application needs to be able to post to https and preserve the session that is created with cookies. So far, i have several different ways of trying the problem and none are working. Currently i am looking into using DefaultHttpClient because it is supposed to automatically preserve sessions created with cookies. This saves me the pain of reading the cookie and submitting with every other post. However, when i try to post using the code i have, the post fails with a certificate error that is listed below.

I had this certificate error earlier with another way i was trying to solve the problem and got it working with HttpsURLConnection, but that does not preserve sessions with cookies automatically.

Can someone please take a look at my code and tell me what i am doing wrong, what i can do better and what needs to change to get it to work.? THANKS!!

I have been trying to solve this problem for a few days now and i am getting know where. Every time i get a little further i get pushed further back. Can someone please assist me! =)

//my posting function
    private static String post(String urlString, List<NameValuePair> nameValuePairs)
    throws MalformedURLException, ProtocolException, IOException {
        DataOutputStream ostream = null;

        HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

        DefaultHttpClient client = new DefaultHttpClient();

        SchemeRegistry registry = new SchemeRegistry();
        SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
        socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
        registry.register(new Scheme("https", socketFactory, 443));
        SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
        DefaultHttpClient http = new DefaultHttpClient(mgr, client.getParams());

        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

        HttpPost httppost = new HttpPost(urlString);

        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        HttpResponse response = http.execute(httppost);

        return response.toString();
}

//the error
04-12 00:37:43.941: WARN/System.err(284): javax.net.ssl.SSLException: Not trusted server certificate
04-12 00:37:43.961: WARN/System.err(284):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
04-12 00:37:43.961: WARN/System.err(284):     at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92)
04-12 00:37:43.970: WARN/System.err(284):     at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
04-12 00:37:43.980: WARN/System.err(284):     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:164)
04-12 00:37:43.980: WARN/System.err(284):     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
04-12 00:37:43.992: WARN/System.err(284):     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
04-12 00:37:44.000: WARN/System.err(284):     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
04-12 00:37:44.000: WARN/System.err(284):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
04-12 00:37:44.000: WARN/System.err(284):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
04-12 00:37:44.020: WARN/System.err(284):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
04-12 00:37:44.020: WARN/System.err(284):     at cpe495.smartapp.SmartDBHelper.post(SmartDBHelper.java:208)
04-12 00:37:44.030: WARN/System.err(284):     at cpe495.smartapp.SmartDBHelper.authenticate(SmartDBHelper.java:105)
04-12 00:37:44.030: WARN/System.err(284):     at cpe495.smartapp.DataSender.submitData(DataSender.java:28)
04-12 00:37:44.040: WARN/System.err(284):     at cpe495.smartapp.DataSender.sendData(DataSender.java:21)
04-12 00:37:44.051: WARN/System.err(284):     at cpe495.smartapp.SmartApp$1.dataReceivedReceived(SmartApp.java:60)
04-12 00:37:44.061: WARN/System.err(284):     at cpe495.smartapp.ConnectDevice.fireDataReceivedEvent(ConnectDevice.java:287)
04-12 00:37:44.061: WARN/System.err(284):     at cpe495.smartapp.ConnectDevice.run(ConnectDevice.java:254)
04-12 00:37:44.071: WARN/System.err(284):     at java.lang.Thread.run(Thread.java:1096)
04-12 00:37:44.071: WARN/System.err(284): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
04-12 00:37:44.090: WARN/System.err(284):     at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
04-12 00:37:44.100: WARN/System.err(284):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
04-12 00:37:44.110: WARN/System.err(284):     ... 17 more
04-12 00:37:44.110: WARN/System.err(284): Caused by: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
04-12 00:37:44.129: WARN/System.err(284):     at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:149)
04-12 00:37:44.150: WARN/System.err(284):     at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
04-12 00:37:44.150: WARN/System.err(284):     at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
04-12 00:37:44.150: WARN/System.err(284):     ... 18 more

回答1:

This issue is due to the fact that the client application is not able to validate build a certificate path from a trust anchor (a root trusted certification authority) and the SSL server certificate. Therefore this certificate is not trusted and the SSL handshake fails.

The apache HTTPClient API provides a nice feature which could help you. The SSLSocketFactory constructor can take a KeyStore parameter, contains the trusted certificates.

Then you can:

  1. create a KeyStore with keytool containing either the root CA certificate or the server certificate directly.
  2. add this keystore to your application
  3. builds the SSLSocketFactory with this KeyStore

For all technical details and code snippets you can read this blog post from Bob Lee: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html