Android HTTPS Post - Not working

2020-06-28 09:37发布

I've been trying for ages to get this to work - but no matter what I do, my HTTP*S* POST always yields HttpUtils: javax.net.ssl.SSLException: Not trusted server certificate

Basically I followed this tutorial

  • I successfully grabbed the public certificate (mycert.pem) from the server.
  • I successfully created a keystore from the certificate using Bouncy Castle
  • I failed at implementing a custom Apache HttpClient. Here is my code:

    import android.content.Context;
    import org.apache.http.conn.ClientConnectionManager;
    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.impl.client.DefaultHttpClient;
    import org.apache.http.impl.conn.SingleClientConnManager;
    import org.apache.http.params.HttpParams;
    import java.io.InputStream;
    import java.security.KeyStore;
    
    public class MyHttpClient extends DefaultHttpClient {
      final Context context;
    
      public MyHttpClient(Context context) {
        this.context = context;
      }
    
      public MyHttpClient(Context context2, HttpParams myParams) {
          super(myParams);
          this.context= context2;
    }
    
    @Override protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(
            new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
      }
    
      private SSLSocketFactory newSslSocketFactory() {
        try {
          KeyStore trusted = KeyStore.getInstance("BKS");
          InputStream in = context.getResources().openRawResource(R.raw.mystore);
          try {
            trusted.load(in, "password".toCharArray());
          } finally {
            in.close();
          }
          return new SSLSocketFactory(trusted);
        } catch (Exception e) {
          throw new AssertionError(e);
        }
      }
    }
    

    And in my HTTP Request class that constructs the POST:

    public class HttpRequest {
    MyHttpClient httpClient;
    HttpContext localContext;
    private String ret;
    
    HttpResponse response = null;
    HttpPost httpPost = null;
    HttpGet httpGet = null;
    
    public HttpRequest(Context context){
        HttpParams myParams = new BasicHttpParams();
    
        HttpConnectionParams.setConnectionTimeout(myParams, 10000);
        HttpConnectionParams.setSoTimeout(myParams, 10000);
        httpClient = new MyHttpClient(context, myParams);       
        localContext = new BasicHttpContext();    
    }
    
    public String sendPost(String url, String data, String contentType) {
        ret = null;
    
        httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
    
        httpPost = new HttpPost(url);
        response = null;
    
        StringEntity tmp = null;        
    
        httpPost.setHeader("User-Agent", "SET YOUR USER AGENT STRING HERE");
        httpPost.setHeader("Accept", "text/html,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
    
        if (contentType != null) {
            httpPost.setHeader("Content-Type", contentType);
        } else {
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
        }
    
        try {
            tmp = new StringEntity(data,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            Log.e("Log", "HttpUtils : UnsupportedEncodingException : "+e);
        }
    
        httpPost.setEntity(tmp);
    
        try {
            response = httpClient.execute(httpPost,localContext);
    
            if (response != null) {
                ret = EntityUtils.toString(response.getEntity());
            }
        } catch (Exception e) {
            Log.e("Log", "HttpUtils: " + e);
        }
    
        return ret;
    }
    }
    

My POST works fine for non-https websites. Any help would be greatly appreciated it.

3条回答
Explosion°爆炸
2楼-- · 2020-06-28 10:20

Use This Class To get Your HttpClient.And Check if it helps.

package com.android.MyCellFamily.DAHttp;

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;

import org.apache.http.HttpVersion;
import org.apache.http.conn.ClientConnectionManager;
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.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

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


public static DefaultHttpClient 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();
    }
}
}
查看更多
够拽才男人
3楼-- · 2020-06-28 10:22

Sometimes https url shows blank white screen in the android webview. It's because you have to trust the ssl certification or you need to override the ssl error in your webview client.

The following webview client provides the needed functions to access https url. here shouldOverrideUrlLoading is used for to allow the redirecting url within the webview, onReceivedSslError this oneiIgnore SSL certificate errors to access the https url.


Webviewclient:

private class MyWebViewClient extends WebViewClient 
             {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            System.out.println("onPageStarted: " + url);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView webView, String url) {
            System.out.println("shouldOverrideUrlLoading: " + url); 
            webView.loadUrl(url);
            return true;
        }

        @Override
        public void onPageFinished(WebView webView, String url) {
            System.out.println("onPageFinished: " + url);               

        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler,
                SslError error) {
            handler.proceed(); // Ignore SSL certificate errors
        }   

    }
查看更多
霸刀☆藐视天下
4楼-- · 2020-06-28 10:24

Look at the error message:

HttpUtils: javax.net.ssl.SSLException: Not trusted server certificate

This means exactly what it says -- the server is not using a trusted certificate. I bet you'll get similar errors if you try to access the same server with Firefox or IE.

查看更多
登录 后发表回答