如何避免Android App的HTTPS API被抓包工具捕获?
如何防止Android应用的SSL API被抓包工具捕获
嘿,这个问题我太熟悉了——很多开发者都会碰到这种情况:自己的App装了用户的第三方CA证书后,HTTPS流量就被Fiddler、Charles这类工具扒得一干二净,而有些大厂App却能防住。核心原因就是那些App做了**证书固定(Certificate Pinning)**和其他防护措施,下面我给你拆解具体怎么做,结合你用Let's Encrypt的情况来优化:
1. 核心手段:实施证书固定
这是最有效的防抓包方法,简单说就是让你的App只认你指定的Let's Encrypt证书,不管系统里装了什么第三方CA。
两种实现方式,按需选择:
- 静态固定(适合小团队/快速落地):把Let's Encrypt证书的哈希值(或者公钥哈希)硬编码到App里。每次发HTTPS请求时,App会自动核对服务器返回的证书哈希是否和硬编码的一致,不一致就直接断开连接。
比如用OkHttp的话,代码大概是这样:
👉 划重点:Let's Encrypt的证书是90天有效期的,如果你固定的是证书哈希,到期后App就连不上服务器了!所以更推荐固定公钥哈希——Let's Encrypt renew证书时公钥不会变,这样就不用每次证书更新都发版本了。CertificatePinner certificatePinner = new CertificatePinner.Builder() .add("your-domain.com", "sha256/这里替换成你的Let's Encrypt证书公钥哈希") .build(); OkHttpClient client = new OkHttpClient.Builder() .certificatePinner(certificatePinner) .build(); - 动态固定(适合有服务器能力的团队):从你的后端服务器定期获取合法证书的哈希,更新到App里。这种方式能避免静态固定的有效期问题,但要注意更新过程本身得是安全的,别被攻击者篡改了更新内容。
2. 让App只信任你指定的证书
默认情况下,Android App会用系统的信任存储,里面包含了用户装的第三方CA。你可以让App完全用自己内置的信任存储,只放Let's Encrypt的根证书/中间证书,这样就算用户装了Fiddler的证书,App也不认它。
还是用OkHttp举例子,代码大概是这样:
// 把Let's Encrypt的根证书放到raw资源文件夹里 InputStream certInputStream = getResources().openRawResource(R.raw.lets_encrypt_root_cert); CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); X509Certificate letsEncryptCert = (X509Certificate) certFactory.generateCertificate(certInputStream); certInputStream.close(); // 创建自己的信任存储 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry("lets_encrypt", letsEncryptCert); // 初始化TrustManager TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); // 配置SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); // 给OkHttp设置自定义的SSL套接字工厂 OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0]) .build();
3. 检测并阻止代理连接
抓包工具必须依赖代理才能截获流量,所以你可以在App里加个检测逻辑,如果发现用户开了系统代理或者App代理,就拒绝发起请求,或者给用户提示。
检测代理的代码示例:
String httpProxyHost = System.getProperty("http.proxyHost"); int httpProxyPort = Integer.parseInt(System.getProperty("http.proxyPort", "-1")); String httpsProxyHost = System.getProperty("https.proxyHost"); int httpsProxyPort = Integer.parseInt(System.getProperty("https.proxyPort", "-1")); if ((httpProxyHost != null && httpProxyPort != -1) || (httpsProxyHost != null && httpsProxyPort != -1)) { // 检测到代理,这里可以弹出警告、终止请求或者直接退出 Toast.makeText(this, "检测到代理配置,无法正常连接服务器", Toast.LENGTH_LONG).show(); return; }
4. 加固App,提高逆向成本
- 确保发布版本的App禁用调试模式:Android Studio的release构建默认会把
AndroidManifest.xml里的android:debuggable设为false,别手动改回来。 - 用ProGuard/R8做代码混淆:把你的代码打乱,让攻击者很难逆向分析出证书固定的逻辑,也就不容易绕过了。
5. 升级TLS配置,减少漏洞
让你的服务器和App只支持TLS 1.3和强加密套件,降低被破解的风险。比如在OkHttp里指定TLS版本:
ConnectionSpec modernTlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_3) .build(); OkHttpClient client = new OkHttpClient.Builder() .connectionSpecs(Collections.singletonList(modernTlsSpec)) .build();
最后提醒
这些措施都是提高攻击门槛,没办法完全阻止有经验的攻击者(比如他们可以逆向修改App代码绕过证书固定),但对付普通的抓包场景已经足够了。另外,证书固定一定要测试到位,别因为配置错了哈希导致用户连不上服务器!
内容的提问来源于stack exchange,提问作者rustin peter
相关产品推荐
相关产品推荐

