尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Android OkHttp安全配置:从信任自签名证书到防御中间人攻击

Android OkHttp安全配置:从信任自签名证书到防御中间人攻击 1. 为什么需要处理自签名证书在Android开发中使用HTTPS进行网络通信已经成为标配。系统默认会信任由权威CA机构颁发的证书比如Lets Encrypt、DigiCert等。但开发测试阶段很多团队会使用自签名证书来节省成本。这时候就会遇到一个典型问题SSLHandshakeException。我第一次遇到这个问题时也很困惑明明服务端配置了HTTPS为什么Android客户端就是连不上后来发现是因为自签名证书没有经过CA机构认证Android系统无法自动验证其合法性。这就好比你去银行办业务工作人员要求你出示身份证但你拿的是自己手写的身份证银行当然不会认可。2. 自签名证书的生成与配置2.1 生成自签名证书生成自签名证书其实很简单使用JDK自带的keytool工具即可。我在终端里执行了以下命令keytool -genkey -alias my_server -keyalg RSA -keystore my_server.jks -validity 3600 -storepass 123456这条命令会生成一个包含公私钥对的密钥库文件my_server.jks有效期为10年。接着导出证书keytool -export -alias my_server -file my_server.cer -keystore my_server.jks -storepass 1234562.2 配置Tomcat服务器为了让本地测试环境支持HTTPS我配置了Tomcat服务器。在conf/server.xml中添加了Connector配置Connector SSLEnabledtrue acceptCount100 clientAuthfalse disableUploadTimeouttrue enableLookupstrue keystoreFile/path/to/my_server.jks keystorePass123456 maxSpareThreads75 maxThreads200 minSpareThreads5 port8443 protocolorg.apache.coyote.http11.Http11NioProtocol schemehttps securetrue sslProtocolTLS /启动Tomcat后访问https://localhost:8443会看到浏览器安全警告这正是我们预期的效果。3. OkHttp的三种信任策略3.1 信任所有证书仅限测试在测试环境下最快捷的方式是让OkHttp信任所有证书。我创建了一个特殊的TrustManagerprivate static X509TrustManager createTrustAllTrustManager() { return new X509TrustManager() { Override public void checkClientTrusted(X509Certificate[] chain, String authType) {} Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }; }配合这个TrustManager创建OkHttpClientOkHttpClient client new OkHttpClient.Builder() .sslSocketFactory(sslSocketFactory, trustManager) .hostnameVerifier((hostname, session) - true) .build();注意这种方式会完全禁用SSL验证存在严重安全风险绝对不要在生产环境使用3.2 信任指定证书推荐方案更安全的做法是只信任特定的自签名证书。首先将证书文件my_server.cer放到assets目录或者将其内容转为字符串String certStr -----BEGIN CERTIFICATE-----\n MIIDOzCCAiOgAwIBAgIEXZVqZDANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJo\n ...省略其余内容...\n -----END CERTIFICATE-----;然后创建只信任该证书的TrustManagerprivate static X509TrustManager createTrustCustomTrustManager(InputStream inputStream) { try { CertificateFactory factory CertificateFactory.getInstance(X.509); Certificate cert factory.generateCertificate(inputStream); KeyStore keyStore KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); keyStore.setCertificateEntry(ca, cert); TrustManagerFactory tmf TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); return (X509TrustManager)tmf.getTrustManagers()[0]; } catch (Exception e) { e.printStackTrace(); return null; } }3.3 证书锁定Certificate Pinning对于安全性要求极高的应用可以使用证书锁定技术。OkHttp原生支持这个功能CertificatePinner pinner new CertificatePinner.Builder() .add(example.com, sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) .build(); OkHttpClient client new OkHttpClient.Builder() .certificatePinner(pinner) .build();这里的sha256指纹可以通过以下命令获取openssl x509 -in my_server.cer -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base644. 防御中间人攻击实战4.1 中间人攻击原理中间人攻击MITM是指攻击者在客户端和服务器之间拦截通信。常见工具如Fiddler、Charles都是利用这个原理实现HTTPS抓包。它们会动态生成自签名证书如果客户端无条件信任所有证书就会导致安全漏洞。4.2 安全配置方案在我的一个金融类App项目中我们采用了以下防御措施生产环境禁用信任所有证书通过BuildConfig.DEBUG区分环境使用证书锁定预置服务器证书指纹定期更换证书每季度更新一次证书指纹动态更新机制通过安全通道下发新证书指纹核心代码如下public class SafeHttpClient { private static final String PIN_SHA256 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; public static OkHttpClient create(Context context) { OkHttpClient.Builder builder new OkHttpClient.Builder(); if (!BuildConfig.DEBUG) { // 生产环境启用证书锁定 builder.certificatePinner(new CertificatePinner.Builder() .add(api.mybank.com, PIN_SHA256) .build()); // 使用系统默认信任管理器 builder.sslSocketFactory(getSystemDefaultSSLContext().getSocketFactory(), getSystemDefaultTrustManager()); } else { // 测试环境允许使用自签名证书 builder.sslSocketFactory(createCustomSSLSocketFactory(context), createCustomTrustManager(context)); } return builder.build(); } private static X509TrustManager getSystemDefaultTrustManager() { try { TrustManagerFactory tmf TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init((KeyStore) null); return (X509TrustManager) tmf.getTrustManagers()[0]; } catch (Exception e) { throw new RuntimeException(e); } } }5. 测试环境与生产环境的最佳实践根据我的项目经验建议采用以下策略环境证书策略抓包支持风险等级开发信任所有证书允许高测试信任指定自签名证书可控允许中预发布系统默认信任证书锁定禁止低生产严格证书锁定禁止最低在代码实现上可以通过BuildConfig灵活切换OkHttpClient createHttpClient() { OkHttpClient.Builder builder new OkHttpClient.Builder(); if (BuildConfig.DEBUG) { // 调试配置 builder.sslSocketFactory(debugSSLSocketFactory, debugTrustManager) .hostnameVerifier((host, session) - true); } else { // 生产配置 builder.certificatePinner(productionPinner) .sslSocketFactory(productionSSLSocketFactory, productionTrustManager); } return builder.build(); }6. 常见问题排查在实际项目中我遇到过几个典型问题证书过期表现为突然无法连接。解决方案是提前监控证书有效期建立更新机制。域名不匹配错误信息包含Hostname not verified。检查证书的CN和SAN字段是否包含当前域名。证书链不完整服务器没有返回完整的证书链。可以通过OpenSSL检查openssl s_client -connect example.com:443 -showcertsAndroid 7.0的网络安全配置从Android 7开始系统不再信任用户添加的证书除非在网络安全配置中明确声明network-security-config domain-config domain includeSubdomainstrueexample.com/domain trust-anchors certificates srcuser / /trust-anchors /domain-config /network-security-config7. 性能优化建议SSL握手会增加网络延迟我在优化一个高频交易App时总结了几点经验会话复用启用OkHttp的连接池和会话复用new OkHttpClient.Builder() .connectionPool(new ConnectionPool(5, 10, TimeUnit.MINUTES)) .build();OCSP装订让服务器在TLS握手时附带OCSP响应减少客户端验证时间HTTP/2支持多路复用可以大幅提升HTTPS性能证书优化使用ECC证书替代RSA证书减小证书体积经过这些优化我们的平均HTTPS握手时间从800ms降到了200ms以下。
返回列表