记录一次开启 OCSP stapling 解决app内webview加载慢的问题 letsencrypt

6,626 阅读6分钟

再次更新

  • 目前发现是因为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协议的介绍可以查看wiki https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol

OCSP的问题

  • 可以在wiki中看到,OCSP也是有他的问题
  1. 隐私问题
  • OCSP检查为某些用户带来了隐私问题,因为它要求客户端与第三方(尽管客户端软件供应商信任的一方)联系以确认证书的有效性。
  1. 性能问题
  • 客户端在TLS握手前需要访问OCSP的检查url,造成阻塞

浏览器的支持

  • 可以在wiki中看到
  • 大多数主要浏览器对OCSP都有广泛的支持:
  1. Internet Explorer的是建立在CryptoAPI的的的Windows从而与首发7版本的Windows Vista中(不是XP [7] )支持OCSP检查。[8]
  2. Mozilla Firefox的所有版本均支持OCSP检查。Firefox 3默认情况下启用OCSP检查。[9]
  3. macOS上的Safari支持OCSP检查。从Mac OS X 10.7(Lion)开始默认启用。在此之前,必须先在“钥匙串”偏好设置中手动激活它。[10]
  4. Opera 从8.0开始支持OCSP检查
  5. 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包迷路了(或者直接被丢包了)