android volley 验证 ssl 证书

标签 android ssl https android-volley

我正在使用 HTTPS 协议(protocol)连接我的服务器,并通过 volley 使用 ssl 证书。我能够连接到服务器并且一切正常。 问题是当我在我的设备上设置代理服务器并在我的 mac 上运行 mimaproxy 时,我可以在 mimaprxy 工具中看到所有的 api。如何防止在 mimaproxy 中显示 api。在阅读了一些关于 HTTPS 和 SSL 的想法后,我知道客户端应该验证 SSL 证书,如果它不是授权的,那么客户端不应该进行 api 调用,我不明白如何使用 volley 来做到这一点。我在谷歌上搜索了很多没有运气:(

我测试了 OLA UBER 和 MERU 他们这样做,我无法在 mimaproxy 中看到 API 调用,因为如果在设备上设置了代理,这些应用程序不会进行 API 调用

谁能帮我解决这个问题,我对httpsssl 了解不多

我的代码如下。

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public void request(final BaseNetData baseNetData, final MyNetCallbacks myNetCallbacks) {
        Log.d(TAG, " Getting url : " + baseNetData.getUrl());
        Log.d(TAG, " Method : " + baseNetData.getMethod());

    final StringRequest strReq = new StringRequest(baseNetData.getMethod(), baseNetData.getUrl(), new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            Log.d(TAG, "onResponse : " + response);
            //My Code
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.d(TAG, "inside onErrorResponse : " + error);
            //My Code
        }
    }) {
        @Override
        public byte[] getBody() throws AuthFailureError {
            Log.d(TAG, "Body : " + new String(baseNetData.getBody()));
            return baseNetData.getBody();
        }

        @Override
        public String getBodyContentType() {
            return baseNetData.getContentType();
        }

        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {
            Log.d(TAG, "  inside parseNetworkResponse, responseCode : " + response.statusCode);
            // My Code
            return super.parseNetworkResponse(response);
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Util.displayMap(TAG, baseNetData.getHeaders());
            return baseNetData.getHeaders();
        }
    };
    BaseApplication.getInstance().addToRequestQueue(strReq, hurlStack, "");
}


HurlStack hurlStack = new HurlStack() {
    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url);
        try {
            httpsURLConnection.setSSLSocketFactory(getSSLSocketFactory());
            httpsURLConnection.setHostnameVerifier(getHostnameVerifier());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return httpsURLConnection;
    }
};

private HostnameVerifier getHostnameVerifier() {
    return new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            //return true;
            HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
            return hv.verify("myhost.com", session);
        }
    };
}

private SSLSocketFactory getSSLSocketFactory()
        throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException, java.security.cert.CertificateException {
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = BaseApplication.getInstance().getResources().openRawResource(R.raw.ca_certificate); // this cert file stored in \app\src\main\res\raw folder path

    Certificate ca = cf.generateCertificate(caInput);
    caInput.close();

    KeyStore keyStore = KeyStore.getInstance("BKS");
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, wrappedTrustManagers, null);

    return sslContext.getSocketFactory();
}

private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
    final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
    return new TrustManager[]{
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return originalTrustManager.getAcceptedIssuers();
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    try {
                        originalTrustManager.checkClientTrusted(certs, authType);
                    } catch (CertificateException ignored) {
                    }
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    try {
                        originalTrustManager.checkServerTrusted(certs, authType);
                    } catch (CertificateException ignored) {
                    }
                }
            }
    };
}

最佳答案

创建一个可以处理 SSL 场景的 HTTP 客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.security.KeyStore;
import java.util.ArrayList;

import javax.net.ssl.HostnameVerifier;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
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.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.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import com.example.firstapp.R;

public class SimpleHttpClient {
 /** The time it takes for our client to timeout */
    public static final int HTTP_TIMEOUT = 30 * 1000; // milliseconds

    /** Single instance of our HttpClient */
    private static HttpClient mHttpClient;

    /**
     * Get our single instance of our HttpClient object.
     *
     * @return an HttpClient object with connection parameters set
     */
    private static HttpClient getHttpClient() {
        if (mHttpClient == null) {
         //sets up parameters
            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, "utf-8");
            params.setBooleanParameter("http.protocol.expect-continue", false);
            //registers schemes for both http and https
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", newSslSocketFactory(), 443));
            ClientConnectionManager manager = new ThreadSafeClientConnManager(params, registry);
            mHttpClient = new DefaultHttpClient(manager, params);
        }
        return mHttpClient;
    }

    private static SSLSocketFactory newSslSocketFactory() {
        try {
          KeyStore trusted = KeyStore.getInstance("BKS");
          InputStream in = LoginLayout.getAppContext().getResources().openRawResource(R.raw.keystore);
          try {
         // Keystore password comes in place of 222222
            trusted.load(in, "222222".toCharArray());
          } finally {
            in.close();
          }
          /*
           * If you use STRICT_HOSTNAME_VERIFIER, the the host name in the URL should match with
           * the host name in the server certificate. In this application it is 192.168.1.3
           * 
           * If you do not want to check the host name and simply want to connect to the URL, then use ALLOW_ALL_HOSTNAME_VERIFIER
           * 
           */
          //HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
          HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
          SSLSocketFactory socketFactory = new SSLSocketFactory(trusted);
          socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
          return socketFactory;
        } catch (Exception e) {
          throw new AssertionError(e);
        }
      }

    /**
     * Performs an HTTP Post request to the specified url with the
     * specified parameters.
     *
     * @param url The web address to post the request to
     * @param postParameters The parameters to send via the request
     * @return The result of the request
     * @throws Exception
     */
    public static String executeHttpPost(String url, ArrayList<NameValuePair> postParameters) throws Exception {
        BufferedReader in = null;
        try {
            HttpClient client = getHttpClient();
            HttpPost request = new HttpPost(url);
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters);
            request.setEntity(formEntity);
            HttpResponse response = client.execute(request);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();

            String result = sb.toString();
            return result;
        }
        finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Performs an HTTP GET request to the specified url.
     *
     * @param url The web address to post the request to
     * @return The result of the request
     * @throws Exception
     */
    public static String executeHttpGet(String url) throws Exception {
        BufferedReader in = null;
        try {
            HttpClient client = getHttpClient();
            HttpGet request = new HttpGet();
            request.setURI(new URI(url));
            HttpResponse response = client.execute(request);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();

            String result = sb.toString();
            return result;
        }
        finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

完整的实现可以在这个 Reference Link 中找到

关于android volley 验证 ssl 证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36003417/

相关文章:

c# - 如何使用 Wireshark 解密从 C# HTTP 客户端发送的 HTTPS 消息?

php - 说明 file_get_contents ('php://input' )

java - 线程 6,RECV TLSv1 警报 : fatal, 握手失败

使用 SSL 在 Azure 网站上使用 Node.js 聊天

apache - 如何在 ubuntu 18.04 服务器的 apache2 下使用 SSL 保护 Jenkins 端口 8080?

redirect - fiddler 将 https 重定向到本地主机

Android:何时使用 Service 与 Singleton?

android - Kotlin (Android) RecyclerView 中不需要的复选框选择

android - 删除 ImageView 的阴影

java - 在 tomcat 连接器中指定 slImplementationName