Android - OkHttp 访问 https 的怪问题

news/2024/9/23 18:24:33/

一、简述

最近使用 OkHttp 访问 https 请求时,在个别 Android 设备上遇到了几个问题,搜罗网上资料,经过一番实践后,问题得到了解决,同时,我也同步升级了我的 https 证书忽略库 ANoSSL ,在此,对搜集到的资料和问题解决方案做个记录。

文章中的代码实现可到 GitHub 仓库中自行获取:

  • https://github.com/GitLqr/ANoSSL

二、协议

要想让 OkHttp 支持 https 请求,需要先对 https 证书协议以及 OkHttp 的支持情况有个大概了解:

  1. 【服务端】https 证书是配置在服务端的,大体分为 SSLTLS 两种协议,TLS (Transport Layer Security) 是 SSL 的升级版本,可以修复现有的 SSL 漏洞。
  2. 【客户端】OkHttp 支持过的 https 证书协议有 SSLv3 (1996)、TLSv1 (1999)、TLSv1.1 (2006)、TLSv1.2 (2008) 和 TLSv1.3 (2018),但要注意,OkHttp 从 2014 年开始就放弃对 SSLv3 支持,2019 年(3.13.x)开始放弃对 TLSv1TLSv1.1 的支持,以 TLSv1.2 为最低支持标准。

资料来源:

  • https://aws.amazon.com/cn/compare/the-difference-between-ssl-and-tls/
  • https://medium.com/square-corner-blog/okhttp-3-13-requires-android-5-818bb78d07ce

我找了几个网站,它们支持的 https 证书协议支持情况如下:

支持协议www.baidu.comwww.fresco-cn.orgapi.github.com
TLS1.3NoNoYes
TLS1.2YesYesYes
TLS1.1YesYesNo
TLS1.0YesYesNo
SSL3.0YesNoNo
SSL2.0NoNoNo

数据来源:

  • https://www.ssleye.com/ssltool/cipher_suites.html
  • https://www.ssllabs.com/ssltest/

可以看到,这几个网站都支持 TLS1.2,而对于其他的 ssl 协议的支持力度各不相同,目前来说,TLS1.2 才是主流,但有可能存在个别网站不支持,所以,我们在使用 OkHttp 发起 https 请求之前,首先要搞清楚,就是服务端(接口)支持的 ssl 协议有哪些。确认好服务端的 ssl 协议支持情况后,就可以开始配置客户端的 OkHttp 了。

三、配置

这里有个问题,是否只要发送 https 请求,就一定需要给 OkHttp 配置 https 校验呢?答案是非必须的,正常情况下 OkHttp 会使用默认的系统配置,用于访问一般的 https 请求足以,但往往有一些特殊情况,就需要我们在工程中进行单独配置并实现校验规则,例如以下几种情况:

  1. 服务端使用了非 CA 认证的私有 https 证书
  2. 服务端使用了过期的 https 证书
  3. 客户端支持某个 ssl 协议但是默认没有启用

好了,下面开始对 OkHttp 进行配置,大体分两步:

  1. 配置 SSLSocketFactory:用于指定支持某种 ssl 协议的 SocketFactory
  2. 配置 HostnameVerifier:用于检查证书中的主机名与使用该证书的服务器的主机名是否一致
val sslSocketFactory = NoSSLSocketClient.getTLSSocketFactory()
val x509TrustManager = NoSSLSocketClient.getX509TrustManager()
val hostnameVerifier = NoSSLSocketClient.getHostnameVerifier()val okHttpClient = OkHttpClient.Builder().sslSocketFactory(sslSocketFactory,x509TrustManager // 必须指定该参数,否则 Android 10 及以上版本会闪退).hostnameVerifier(hostnameVerifier).build()

这里主要看 sslSocketFactory 是怎么创建的,前面说过,https 证书大体分为 SSLTLS 两种协议,这里的 SSLSocketFactory 也一样,以下是两种协议对应的创建方式,它们仅仅只是在获取 SSLContext 实例时传的参数不同而已:

// SSL(不推荐)
public static SSLSocketFactory getSSLSocketFactory() {try {SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(

http://www.ppmy.cn/news/1429238.html

相关文章

Java基于微信小程序的讲座预约系统的研究与实现,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

纵行科技携ZETA传感器亮相深圳国际传感器与应用技术展览会

传感器是物联网时代的核心组成部分,在数字化转型和智能化趋势的推动下,全球传感器创新加速,市场持续增长,规模不断扩大。2024年4月14-16日,深圳国际传感器与应用技术展览会,在深圳会展中心(福田…

TCP 协议特性

1. TCP 基本认识 TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的; 可靠的:无论的网络链…

【UnityShader】图片圆角

1.需求 我们在开发的时候,有时候一些按钮或者菜单栏的边角是直角的需要改成圆角,但是让美术重新绘制耽误时间不说也确实没必要,这个时候我们不妨使用一个简单的shader去解决这个问题,下面我们就讲讲这个shader要如何实现。 需求1…

使用51单片机控制T0和T1分别间隔1秒2秒亮灭逻辑

#include <reg51.h>sbit LED1 P1^0; // 设置LED1灯的接口 sbit LED2 P1^1; // 设置LED2灯的接口unsigned int cnt1 0; // 设置LED1灯的定时器溢出次数 unsigned int cnt2 0; // 设置LED2灯的定时器溢出次数// 定时器T0 void Init_Timer0() {TMOD | 0x01;; // 定时器…

Qt——Qt网络编程之TCP通信服务器端的实现(使用QTcpServer、QTcpSocket实现一个TCP服务器端例程)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实战》

Docker中Kafka容器创建/更新Topic支持多分区

前提 自行通过docker部署好kafka&#xff0c;并启动相关容器。 假设Topic为http_capture。 #docker-kafka kafka_dir/opt/docker/kafka/build sudo rm -rf ${kafka_dir}/* cat > ${kafka_dir}/docker-compose.yml <<EOF version: "3.3" services:zookeepe…

单例模式与反射创建对象

单例模式 饿汉式单例模式 单例模式&#xff0c;就是自己先把自己创建了&#xff0c;整个程序都只有这一个实例&#xff0c;别人都没有办法创建实例&#xff0c;因为他的构造方法是private的 一次性把全部都创建了 public class HungryMan {private static int [][] s new …