HttpClient and custom TrustManager on android
我一直在尝试向apache HttpClient库注册我的自定义TrustManger。 以下链接包含有关如何执行此操作的说明:Https Connection Android
不幸的是,我想使用的构造函数(public SSLSocketFactory(SSLContext sslContext))在Android版本的HttpClient中不可用。 我将使用sslContext初始化我的自定义TrustManager。 似乎Android已将其替换为" KeyStore"。
我的问题是:(如何)我可以在Android的DefaultHttpClient中注册自定义TrustManger? KeyStore类中是否有替代方法?
最终,我现在想忽略证书检查...
请仅考虑HttpClient库,因为我的整个应用程序都基于该库。
解决方案是创建自己的套接字工厂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class NetworkSSLSocketFactory implements LayeredSocketFactory { private SSLContext sslContext; private SSLSocketFactory socketFactory; private X509HostnameVerifier hostnameVerifier; /** * Creates a socket factory that will use the {@link SSLContext} and * {@link X509HostnameVerifier} specified. The SSLContext provided should * have the {@link NetworkTrustManager} associated with it. * * @param sslContext * @param hostnameVerifier */ public NetworkSSLSocketFactory(SSLContext sslContext, X509HostnameVerifier hostnameVerifier) { this.sslContext = sslContext; this.socketFactory = sslContext.getSocketFactory(); this.hostnameVerifier = hostnameVerifier; } } |
然后创建一个使用TrustManager的SSLContext,然后创建一个AndroidHttpClient并将其https模式替换为使用SocketFactory的https模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * Return the SSLContext for use with our HttpClient or create a new Context * if needed. * <p> * This context uses our {@link NetworkTrustManager} * * @return an {@link SSLContext} */ public SSLContext getSSLContext() { if (mSSLContextInstance != null) return mSSLContextInstance; try { mSSLContextInstance = SSLContext.getInstance("TLS"); TrustManager trustManager = new NetworkTrustManager(getKeyStore()); TrustManager[] tms = new TrustManager[] { trustManager }; mSSLContextInstance.init(null, tms, new SecureRandom()); } catch (NoSuchAlgorithmException e) { Log.e(TAG, e.getMessage()); } catch (KeyManagementException e) { Log.e(TAG, e.getMessage()); } return mSSLContextInstance; } |
现在的客户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /** * Return an HttpClient using our {@link NetworkTrustManager} and * {@link NetworkHostnameVerifier} * * @return an {@link HttpClient} */ public HttpClient getHttpClient() { if (mHttpClientInstance != null) return mHttpClientInstance; SSLContext sslContext = getSSLContext(); // Now create our socket factory using our context. X509HostnameVerifier hostnameVerifier = new NetworkHostnameVerifier(); NetworkSSLSocketFactory sslSocketFactory = new NetworkSSLSocketFactory( sslContext, hostnameVerifier); // Some services (like the KSOAP client) use the HttpsURLConnection // class // to establish SSL connections. HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext .getSocketFactory()); // Generate the Client for the Server mHttpClientInstance = AndroidHttpClient.newInstance(getAgent(), mContext); // Get the registry from the AndroidHttpClient and change the // HTTPS scheme to use our socket factory. This way we can // control the certificate authority and trust system. SchemeRegistry schemeRegistry = mHttpClientInstance .getConnectionManager().getSchemeRegistry(); schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); return mHttpClientInstance; } |
如果您不知道如何创建新的密钥库,请执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /** * Get the current KeyStore or if not yet created, create a new one. This * will NOT load the KeyStore file identified by * {@link #KEYSTORE_NAME}. To load the KeyStore file, use the function * {@link #loadKeyStore()} which will automatically call this function (so * you don't need to). * <p> * * @return a {@link KeyStore} */ public KeyStore getKeyStore() { if (mKeyStore != null) return mKeyStore; try { String defaultType = KeyStore.getDefaultType(); mKeyStore = KeyStore.getInstance(defaultType); mKeyStore.load(null, null); } catch (Exception e) { Log.w(TAG, e.getMessage()); } return mKeyStore; } |
上面的解决方案是解决方案的开始,允许您创建一个TrustManager来验证到"系统密钥库"的证书以及您自己的"私人密钥库"(两个密钥库)。然后,您无需尝试将证书添加到系统密钥库。您可以在getFilesDir()文件夹中创建自己的KeyStore。
我仍然没有完成从HttpResult = HttpClient.execute(HttpPost);捕获证书的逻辑。方法,但我现在正在积极编写。如果您需要帮助,我现在可以与您合作。
如果有人知道如何从HttpRequestBase对象内的SSLSocekt捕获/获取证书,请告诉我。我正在努力寻找答案。
实际上,该方法存在但被隐藏。 getHttpSocketFactory()在内部使用它。我只是通过使用反射使它起作用。不安全,但是可以用于开发目的。
1 2 3 | Class<org.apache.http.conn.ssl.SSLSocketFactory> c = org.apache.http.conn.ssl.SSLSocketFactory.class; Constructor<org.apache.http.conn.ssl.SSLSocketFactory> ctor = c.getConstructor(javax.net.ssl.SSLSocketFactory.class); SSLSocketFactory ssf = ctor.newInstance(SSLCertificateSocketFactory.getInsecure(getSSLHandshakeTimeout(), null)); |