【问题标题】:Issue loading Google Map when I limit the internet access to SSL/HTTPS requests当我限制对 SSL/HTTPS 请求的 Internet 访问时,加载 Google 地图时出现问题
【发布时间】:2018-04-28 07:47:45
【问题描述】:

我在我的代码中使用这一行来确保我的应用程序使用我在原始文件夹中的证书文件对服务器进行身份验证。

HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

问题是,如果我添加此行 Google Maps stop loading,如果我删除此行,地图会加载,但我的应用无法连接到 https://XXX.com/ 上的 API登录

当谷歌地图停止加载时,我没有收到任何错误消息。否则,如果我删除上面的行,我会收到 SSLHandshake 错误。我正在使用 Volley 来处理我的网络请求。不知道从这里去哪里。寻求帮助社区!

代码

private SSLSocketFactory getSocketFactory() {

        CertificateFactory cf = null;
        try {

            cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = getResources().openRawResource(R.raw.catchme);
            Certificate ca;
            try {

                ca = cf.generateCertificate(caInput);
                Log.e("sslAuth", "CERT ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }


            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);


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


            HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {

                    Log.e("sslAuth", "CipherUsed "+session.getCipherSuite());
                    Log.e("sslAuth", "hostname "+hostname);
                    if(hostname.compareTo("xxxxxx.com")==0)
                        return true;
                    else if(hostname.compareTo("google.com")==0)
                        return true;
                    else
                        return false;
                }
            };


            HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
            SSLContext context = null;
            context = SSLContext.getInstance("TLS");

            context.init(null, tmf.getTrustManagers(), null);
            HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

            SSLSocketFactory sf = context.getSocketFactory();


            return sf;

        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        return  null;
    }

代码:

public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            //mRequestQueue = Volley.newRequestQueue (getApplicationContext ());
            mRequestQueue = Volley.newRequestQueue(this, new HurlStack(null, getSocketFactory()));
        }

        return mRequestQueue;
    }

【问题讨论】:

  • 为什么要使用静态 SSL 证书?
  • 只是说您的后端开发人员要正确链接证书。你不需要添加静态。
  • 使用此链接检查您的后端是否支持android。ssllabs.com/ssltest
  • 你的意思是我在我的 Raw 文件夹中的证书文件,我应该在 android 代码中根本没有这个文件吗?有没有其他更好的方法来做到这一点?不知道为什么启用此代码后 Google 地图会停止加载...

标签: android google-maps ssl https


【解决方案1】:

我实现了一个涉及 OkHttp 和 Volley 的设置。这个实现创建了一个为 SSL 设置的 OkHttp 客户端。这个客户端被传递给 Volley 以创建请求队列来处理应用程序和数据服务器之间的所有通信。

相比之下,问题中发布的实现为 SSL 设置了全局应用程序客户端。这可以防止 Google 地图通过强制 SSL 设置与其服务器进行通信。希望这可以帮助某人。这是代码。干杯!

创建 Volley RequestQueue:

public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(this, new OkHttpStack());
        }
        return mRequestQueue;
}

OkHttpStack

public class OkHttpStack extends HurlStack {
        private final OkUrlFactory mFactory;

        public OkHttpStack() {
            OkHttpClient client = getCustomOkHttpClient();
            mFactory = new OkUrlFactory(client);
        }

        @Override
        protected HttpURLConnection createConnection(URL url) throws IOException {
            return mFactory.open(url);
        }
    }

getCustomOkHttpClient()

private OkHttpClient getCustomOkHttpClient() {

        OkHttpClient client = new OkHttpClient();
        CertificateFactory cf = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = getResources().openRawResource(R.raw.xxx);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }


            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);


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


            HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {

                    Log.e("CipherUsed", session.getCipherSuite());
                    Log.e("CipherUsed", hostname);
                    //return true;
                    return hostname.compareTo("xxx.com")==0 || hostname.compareTo("zzz.com") == 0;

                }
            };


            client.setHostnameVerifier(hostnameVerifier);
            SSLContext context = null;
            context = SSLContext.getInstance("TLS");

            context.init(null, tmf.getTrustManagers(), null);
            client.setSslSocketFactory(context.getSocketFactory());

            SSLSocketFactory sf = context.getSocketFactory();


            return client;

        } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e) {
            e.printStackTrace();
        }

        return  null;
    }

【讨论】:

    【解决方案2】:

    请尝试以下选项:

    1.

    放置 catch 块
    catch(IllegalStateException ex){
    ex.printStackTrace();
    }
    

    2. 只需尝试为 google.com 安装有效证书。请按照本教程import your ssl certificate files

    3.只需调试出这行代码

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();

    并检查 tmfAlgorithm 值是否与从 google.com 获得的 ssl 证书匹配。

    如果有任何进一步的帮助,请联系。谢谢

    【讨论】:

    • 感谢您的宝贵时间。我不太确定这个过程正在实现什么,但我能闻到成功的味道:) 请您分享一些见解/链接以帮助我了解这些步骤的意图/目的吗?
    【解决方案3】:

    您是否使用相同的 HttpClient 实例来获取 GoogleMaps?

    您应该为后端请求和 Google 请求使用不同的 HttpClient

    我从来没有用过Volley,但我相信你可以做到,在OkHttp中应该是这样的

    //Something like this you should change or add your Interceptors
    public OkHttpClient getHttpClient(){
            OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
            try {
    
            //add your sslSocketFactory and TrustManager    
    httpClient.sslSocketFactory(getSocketFactory(),getTrustManager());
    
                httpClient.addInterceptor(headerInterceptor());
                httpClient.connectTimeout(60, TimeUnit.SECONDS);
                httpClient.writeTimeout(60, TimeUnit.SECONDS);
                httpClient.readTimeout(60,TimeUnit.SECONDS);
            } catch (KeyManagementException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return httpClient.build();
        }
    
    //You should add your trustManager here
    public TrustManager getTrustManager(){
        return new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    
                }
    
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }
    

    【讨论】:

    • 感谢您的回答。此示例演示了使用 OkHttp 为每个 httpClient 实例设置连接约束(SSL/非 SSL 等)。但就我而言,我正在为整个应用程序设置请求约束。我可以使用这个实现,但我不认为 Volley 有类似的方式来为每个请求定义连接约束..
    猜你喜欢
    • 2014-04-15
    • 2018-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2020-01-25
    相关资源
    最近更新 更多