再次更新
- 目前发现是因为
ocsp.int-x3.letsencrypt.org
这个域名dns被污染的原因,暂时没发现该网站被ip封锁或者http劫持 - 如果服务器在境外按下面讲的方法解决就行了.如果服务器在境内,目前的解决方案是
dns over https
简称doh
,在服务器上启动一个doh-client
应用,监听53 udp端口并且将dns请求转发至https://1.1.1.1/dns-query
- 然后将nginx的
resolver
配置改为本地doh-client
提供的dns服务,可以暂时缓解这个问题
发现问题的过程
开始
- 我们有个app,实质是webview打个壳
- 测试发现在某些ios的机器上启动app特别慢
- 在安卓上没有问题,在电脑上用浏览器打开也没问题
- 而且跟ios的机型好像也没关系,部分ios设备特别慢
问题提交给app的开发人员
- 具体测试发现使用http的时候没有问题,使用https就会有问题
接着测试 http2
- 第一个怀疑是http2的问题,因为之前好像曾经有过这个经历.而且在http下是不会使用http2的
- 实验
服务器关闭tls下的http2
,结果问题还在,排除http2的问题
测试nginx的tls配置
- 怀疑可能是nginx某些tls的配置导致的问题,改了各种配置例如
ssl_prefer_server_ciphers
ssl_ciphers
ssl_ecdh_curve
都是一些TLS的密钥交换群和密钥交换算法的配置,都无效
进一步惊人的发现
- 因为我们办公室的wifi使用的是电信的网络,有些测试的手机用的也是电信的卡
- 当使用移动的手机分享热点并给有bug的手机连上之后,问题就解决了,并且有bug的手机在切换回办公室wifi或者电信网络也没有什么问题
猜测
- 猜测是TLS握手过程需要访问某个url,但是在电信下会有问题
抓包
- 对有bug的手机进行抓包,发现了app打开的过程中会去访问
http://ocsp.int-x3.letsencrypt.org
并且非常的慢
准备解决问题
查找资料
- 首先是https的过程,可以参考
https://juejin.cn/post/6844904135230390279
证书的验证
- 在TLS的握手的过程中,服务器把自己的证书给客户端以后,客户端需要验证服务器的证书有效
- 一般采用证书链的方式,一般的网站证书是由CA签发的,而CA的证书是由更高级的CA签发的,最高级的证书一般内置在操作系统和浏览器中,被称作
根证书
,根证书是被无条件信任的 - 这整个链条组成了证书信任链,最后只要在本机中找到根证书,就能确认网站的证书是可以信任的
- 一般为了快速的认证,网站给客户端提供证书的时候,会把整个证书链的证书都一起给.这样客户端不需要额外的网络请求,只需要验证一下,每个证书是否过期,是否由上一级证书签名,并且自己本机有没有对应的根证书即可
- 例如我们网站的证书链是这样的
DST Root CA X3
⤵
Let's Encrypt Authority X3
⤵
我们网站的证书
信任链的问题
- 但是证书信任链条有个问题,一旦证书被签发.证书就会被信任,哪怕证书被泄露或者是被滥用
- 为了解决这个问题,加入了证书吊销的操作,于是就有了查询证书吊销的协议
OCSP
OCSP
协议的介绍可以查看wikihttps://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol
OCSP的问题
- 可以在wiki中看到,OCSP也是有他的问题
- 隐私问题
- OCSP检查为某些用户带来了隐私问题,因为它要求客户端与第三方(尽管客户端软件供应商信任的一方)联系以确认证书的有效性。
- 性能问题
- 客户端在TLS握手前需要访问OCSP的检查url,造成阻塞
浏览器的支持
- 可以在wiki中看到
- 大多数主要浏览器对OCSP都有广泛的支持:
- Internet Explorer的是建立在CryptoAPI的的的Windows从而与首发7版本的Windows Vista中(不是XP [7] )支持OCSP检查。[8]
- Mozilla Firefox的所有版本均支持OCSP检查。Firefox 3默认情况下启用OCSP检查。[9]
- macOS上的Safari支持OCSP检查。从Mac OS X 10.7(Lion)开始默认启用。在此之前,必须先在“钥匙串”偏好设置中手动激活它。[10]
- Opera 从8.0开始支持OCSP检查
- Google Chrome 特立独行,Chrome在2012年就禁止了OCSP检查,理由是延迟和隐私问题.取而代之的是使用自身的方法检查证书的撤销问题.
- 这就是为什么在安卓上不会有问题,而在电脑上,如果你使用的是chrome也不会有这个问题
OCSP问题的解决方案OCSP stapling
- OCSP stapling说白了就是由服务器去请求OCSP信息,并且在握手阶段提供给客户端,使得客户端不需要再去查询OCSP信息
- 这样在客户端TLS握手的时候不需要再去额外请求一个OCSP查询,也就不会被阻塞
问题的解决和分析
- 在nginx的配置中开启 OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 223.5.5.5; #resolver即为dns服务器,必须指定,否则nginx无法解析OCSP的域名,服务器在国内可以使用 223.5.5.5 或者 114.114.114.114 ,服务器在国外可以使用8.8.8.8 或者 1.1.1.1
- 也可以自行下载OCSP返回并配置上
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /your/path/to/chained.pem;
- 具体过程自己google(baidu)
然后问题解决
关于 ocsp.int-x3.letsencrypt.org
- 因为我们使用的是
Let's Encrypt Authority X3
的证书,所以查询OCSP的域名就是http://ocsp.int-x3.letsencrypt.org
- 按道理来说,哪怕服务器不配置OCSP stapling,那么客户端应该会自行去查询OCSP,虽然可能会慢一点,应该也不会这么慢才是
traceroute
- 在电脑上直接访问ocsp.int-x3.letsencrypt.org,会发现有时候访问不了,有时候访问很慢
- 直接traceroute该域名得到以下结果
traceroute to a771.dscq.akamai.net (69.171.242.30), 64 hops max, 72 byte packets
1 192.168.20.1 (192.168.20.1) 0.600 ms 0.341 ms 0.338 ms
2 115.196.136.1 (115.196.136.1) 2.218 ms 3.241 ms 4.372 ms
3 61.164.12.206 (61.164.12.206) 2.465 ms 2.318 ms 2.648 ms
4 61.164.22.141 (61.164.22.141) 3.861 ms 3.106 ms 4.270 ms
5 202.97.26.13 (202.97.26.13) 11.297 ms 12.619 ms 7.708 ms
6 202.97.57.157 (202.97.57.157) 5.853 ms * *
7 * * *
8 * * *
9 * * *
10 * * *
11 * * *
12 * * *
13 * * *
14 * * *
15 * * *
-
在第6跳以后,就没有消息了
-
查询202.97.57.157,为电信在上海的骨干交换网ip
-
而如果网络是移动,就正常
-
初步诊断,原因是因为电信错误的路由策略,导致发往69.171.242.30包迷路了(或者直接被丢包了)