HTTPS 工作原理以及 Android 中如何防止抓包
4. 抓包的原理
平常使用的抓包工具,无论是 fidder 和 charles 都能解析客户端和服务器的 HTTPS 数据,是如何做到的呢?其实抓包工具就充当了一个中间人代理的角色,参照 2.https 的工具原理,抓包的工作原理如下:
截获客户端向发起的 HTTPS 请求,佯装客户端,向真实的服务器发起请求
截获真实服务器的返回,佯装真实服务器,向客户端发送数据
获取了用来加密服务器公钥的非对称秘钥和用来加密数据的对称秘钥
5. Android 中使用 HTTPS 以及如何防止抓包
Android 中如何访问 HTTPS 呢,其实 Retrofit、OkHttp 均支持 HTTPS 的访问 项目中引入网络库,以**implementation 'com.squareup.okhttp3:okhttp:4.2.0'**为例,
final OkHttpClient okHttpClient = new OkHttpClient.Builder().build();final Request request = new Request.Builder().url("https://www.baidu.com/robots.txt").build();final Response execute = okHttpClient.newCall(request).execute();final String bodyStr = execute.body().string();Log.d(TAG, bodyStr);
那如果关闭客户端的 CA 证书,GlobalSign Root CA-R1,相当于不信任百度服务器的数字证书,会导致报错
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
通过手动将GlobalSign Root CA-R1.cer
放入项目中的 assets 文件夹,则可避免这一错误,如何引用项目中集成的证书呢? 通过
SSLContext sslContext;try {InputStream inputStream = getAssets().open("");sslContext = SSLContext.getInstance("TLS");sslContext.init(null, new TrustManager[]{OkhttpU.trustManagerForCertificates(inputStream)}, null);SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory, OkhttpU.trustManagerForCertificates(inputStream)).build();final Request request = new Request.Builder().url("https://www.baidu.com/robots.txt").build();final Response execute = okHttpClient.newCall(request).execute();final String bodyStr = execute.body().string();Log.d(TAG, bodyStr);} catch (Exception e) {e.printStackTrace();}
public class OkhttpU {
public static X509TrustManager trustManagerForCertificates(InputStream in)throws GeneralSecurityException {CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);if (certificates.isEmpty()) {throw new IllegalArgumentException("expected non-empty set of trusted certificates");}
// Put the certificates a key store.char[] password = "password".toCharArray(); // Any password will work.KeyStore keyStore = newEmptyKeyStore(password);int index = 0;for (Certificate certificate : certificates) {String certificateAlias = Integer.toString(index++);keyStore.setCertificateEntry(certificateAlias, certificate);}
// Use it to build an X509 trust manager.KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());keyManagerFactory.init(keyStore, password);TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {throw new IllegalStateException("Unexpected default trust managers:"
Arrays.toString(trustManagers));}return (X509TrustManager) trustManagers[0];}
private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {try {KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());InputStream in = null; // By convention, 'null' creates an empty key store.keyStore.load(in, password);return keyStore;} catch (IOException e) {throw new AssertionError(e);}}}
就可以正常访问 https 了
综上,通过引入自定义证书,然后给 OkHttp 设置 sslSocketFactory 可以有效的防止抓包,但是.cer 放到 assets 下很容易被反编译,可以通过 jdk 下的命令 keytool -printcert -rfc -file srca.cer 导出字符串,然后通过 OkHttpClientManager.getInstance().setCertificates(new Buffer().writeUtf8(CER_STRING) //CER_STRING 是到处的 string 常量.inputStream());相关文章
[一篇文章看明白 HTTP,HTTPS,
SSL/TSL 之间的关系]( )
评论