安卓端出现https请求失败(转)

news2024/11/27 7:40:42

背景#

某天早上,正在一个会议时,突然好几个同事被叫出去了;后面才知道,是有业务同事反馈到领导那里,我们app里面某个功能异常。

具体是这样,我们安卓版本的app是禁止截屏的(应该是app里做了拦截),但部分页面,支持配置成可以截屏。这个配置是通过后端接口获取的,意思就是,如果调用这个接口失败,就整个app默认不能截屏;如果调用成功,就可以在配置的指定页面截屏。

业务反馈就是说,之前可以截屏的几个页面,现在突然不能截屏了,不知道是不是我们搞了啥变更;后面产品去业务那深入了解了下,发现:连接公司wifi后就不能截屏,用4g/5g是可以的。

排查过程#

前期排查#

安卓开发首先介入,具体方式就是,因为可以复现,找了个安卓设备,连接电脑就可以debug app(没搞过安卓,具体不清楚),后面说是获取截屏配置的接口(https)报错了:

ret: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found 

image-20231202110550337

丢出这个后,就没有进一步的动作了,认为不是安卓端的问题,因为用5g就可以,只是wifi不行。然后问题就卡在那了。有人又丢出之前的一个变更通知,那次变更是这样,之前我们https证书卸载都是在业务服务器的nginx做的,这样的话,每个业务都会有自己的nginx,每个nginx都要负责https加解密,后来就提出来,要把这个https加解密前置,后面就前置到了负载均衡设备(比如典型的硬件负载均衡设备:F5)。

有人就说是不是动了这个导致的,虽然这个极有可能,但是,没有人去查,去确认。

后端开始介入#

因为安卓侧认为自己没问题,产品后面来找我,我才开始介入这个问题。

下午先了解了下整个事情,比较重要的事情是,拿到了复现问题的手机,然后试着连接电脑charles进行抓包,才想起来安卓目前抓包非常困难,在电脑端用charles、fiddler这类代理是没有用的;那就只能找安卓开发看这个,我本来预期的是,在他那里,通过debug,要知道这个错误到底是什么导致的,比如是https的哪个阶段,是不是https证书的哪个字段有啥问题,结果,最终和我说的是,这个是底层okhttp的,没法debug到那一层;我其实是对这块持怀疑态度,肯定是有办法的,但可能他不会,从没深入过https这层,所以就说他没办法继续定位到更多信息了。

他么当时火也大,但问题还是得解决(后面我看到货拉拉那个文章里,其实是可以debug那部分代码,不过确实是不在android.jar源码里,在单独的模块中)。

安卓端没法看,电脑端没法用简单的方式抓包,我了解到的一些抓包的办法都是很复杂,不搞安卓开发的话,光是搭环境都要搭半天那种;要么就是在手机上装抓包软件,但有些需要root,且能不能抓https这层检查证书,我也持怀疑态度,我个人又是垃圾iphone,对安卓确实不熟悉。

唯一的办法,就只有:wifi路由器上抓包,或者是找到目前负责https加解密的负载均衡设备的同事,来进行抓包。

搜索引擎查找可能原因#

证书锁定#

拿那个错误,查了下原因,查到一篇货拉拉的文章,感觉比较靠谱。

货拉拉SSL证书踩坑之旅 货拉拉SSL证书踩坑之旅

里面提到,app内部可能内置了服务端的证书,而app在访问https后端建立https连接的过程中,服务端会把自己的证书(一般配置在nginx,我们这边就是负载均衡设备,F5)返回给app,app检查到返回的证书如果和本地内置的不一致,就可能报那个错;

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found 

这个专业术语叫做:证书锁定. (证书锁定SSL Pinning简介及用途 - 知乎)

这种就是可以防止中间人攻击的,如fiddler、charles这类基于代理的,基本就属于中间人攻击,因为charles他们会把自己的证书给我们,我们内置了证书的话,就会发现charles证书和内置证书不一致,就可以主动终止连接。

好些安卓的专业抓包方案,就是基于hook,把证书校验的那些代码都给hook掉,这类方案对于非安卓开发人员还是困难了一点,要一整套工具链,以后换个遥遥领先的话,可以好好折腾下。

另外,如果真用了证书锁定,那么根据货拉拉文章内容,新证书可能少了某个字段,导致这个问题:

image-20231202115202773

检测网站#

亚数信息-SSL/TLS安全评估报告

可以输入自己的网址,检查下,不一定准,我们的问题当时就没查出来。

检查安卓端配置#

可能有如下这个配置文件,看看里面的内容,这里面也涉及一些trust-anchor的内容:

图片

负载均衡设备抓包#

排除后端嫌疑#

次日,我直接找了app端的leader,结果leader反馈说,app没搞证书锁定那些高级玩意,其他配置也检查了,好像没啥问题,所以无疾而终。

然后去找了负载均衡设备的同事,同事还是非常支持,所以,那天下午,我们就在一块,在负载均衡设备上,抓了一下午的包。

他首先怀疑的是,后端服务返回的内容是不是有问题,因为,用他手机尝试时,一会可以截屏,一会不可以,就是没能稳定复现。

于是就抓取负载设备和后端nginx之前的报文,这块我们面临一个问题,负载上流量很大,怎么区分出他手机的流量呢?尤其是现在好多手机都是优先用Ipv6,而目前在百度这种查ip,基本只显示了ipv4

那天我看同事用的ip138.com,我今天又搜了一个:IP查询(ipw.cn) | IPv6测试 | IPv6在线Ping测试 | IPv6网站检测 | IPv6网站测速 | IPv6地址查询 | IP查询(ipw.cn)

都还不错。

1701490193819

所以我们就抓负载和nginx之间的包,包里会有字段带了我们的手机的出口ip:

image-20231202121151609

就用这个字段筛选出我们的流量后,检查发现,后端返回的内容没啥问题。

后面和那个能稳定复现的安卓设备比较,发现是同事手机的app版本低了,艹,升到最新版,就能稳定复现了。

各种场景对比#

后面就开始对比,从公网过来,和从wifi过来的包;再就是,安卓设备端公网出口ip为ipv4和ipv6的,这么一组合,就有4种组合。

后面发现,公网过来的,不管是ipv4还是ipv6,都没问题;从wifi过来的,我们这边测试,好像都是有问题的,但我们也抓包发现了其他人的请求,看着好像是从wifi来的,又没问题的。

这期间其实探索了很多可能性,比如也检查了waf设备(waf设备比负载均衡设备还要靠前,且waf工作在7层,也会涉及https的加解密,我是有怀疑过waf,但当时看了waf的日志啥的,没发现异常)

另外,这期间,我也在自己的云服务器上,尝试了如下方式:

openssl s_client -debug -connect xxx.com.cn:443 tcpdump -i any host xxx.com.cn and tcp port 443 -w 443.pcap 

和负载均衡端侧的抓包进行交叉对比。

对比的场景太多,都记不清了,但最终确定的是,wifi网络下,出口ip是ipv4还是ipv6来着的时候,就有问题。

其实我一开始就是怀疑证书那块可能有问题,但是,也不能在没找到确切原因的时候,贸然对证书进行操作,所以就和负载均衡设备的同事搞了一下午。

虽然当时没确定出根因,但收获包括:

流量情况下,访问xxx.com.cn:443是直接到xxx.com.cn:443的防火墙设备;

wifi下,访问xxx.com.cn:443也是绕到了公司的互联网出口,再去访问xxx.com.cn:443的防火墙设备;

但是,可以肯定的是,这两种情况下,xxx.com.cn:443的防火墙那边,肯定是配置了不同的路由策略,两者的网络路径应该是不一样的,这块就还得找具体负责防火墙的同事来一起看。

本机模拟发现新端倪#

我们不是在负载均衡和nginx那层抓了包吗,那层是明文的,我们就照着那个明文,录入到本机的postman里,调用,发现是成功的。

后来,我想是不是postman没校验证书,所以才成功的,然后找了找,发现确实有这么个选项:

image-20231202132420296

默认是false,不校验,我打卡后,再一请求,果然报错了,不过报的是服务端返回的证书缺少了中间证书。

所谓的中间证书,可以这么理解,目前世界上,有一批权威机构(ROOT CA),他们负责给大家颁发https证书,颁发的证书会给到我们,然后我们就放到服务器上。

浏览器、手机等客户端访问我们时,我们就把证书返回给浏览器等,此时,他们怎么知道我们的证书是真的假的呢,就是靠证书里的颁发者字段,他们找到颁发者,再和自己浏览器内置的或者操作系统中内置的ROOT CA白名单做一个匹配,如果在本机内置的ROOT CA白名单中,就可以认为证书确实是这些权威机构颁发的,值得信赖。(当然,这只是其中的一个检查项,不是全部,比如还要检查证书是否在有效期内,是否已经被吊销了)

但是哈,一般我们的证书,不会是这些ROOT CA直接颁发的,而是ROOT CA下属的某个中间证书颁发的,以下面百度的为例:

image-20231202133132969

此时,百度服务端就必须返回baidu.com这个证书,但是它是由中间证书签发的,而一般操作系统或者浏览器没内置中间证书那些机构,所以,服务端一般要把baidu.com以及中间证书机构的证书,一并返回,这样,才能一层层找到中间证书的签发者,然后发现签发者是root ca的话,就和本机的白名单做对比。

另外,我也在本机对了对照组,postman在两种网络下发请求:

  • 本机pc在公司wifi下,此时,走的是公司wifi
  • 本机pc连接手机的热点,此时,走的是流量网络

对比了下,发现真的有问题:

image-20231202133649730

在这两种情况下,客户端首先发请求(client hello)和服务端协商后续用哪个版本的tls协议。客户端发出去的请求我对比了,除了随机数部分,基本一致,但是,服务端最终协商出来的结果却不一样,一个是tls v1.2 ,一个是tls v.1.3

从这里也验证了,这个xxx.com.cn:443的接入这块(一般接入那里应该是路由器,但一般好像也具有防火墙的功能),会根据客户端的网络来源于wifi和流量,走了不同的路线。

这块也得具体咨询接入这块的同事了。

补齐证书链解决问题#

结果我们后续还没来得及去找接入的同事,负责负载均衡设备的同事跟我说,他把证书链补充完整了,让我再试试。

所谓证书链补齐了的意思是,他之前就是负责将nginx层的证书挪到了负载均衡设备,在他完成这次变更后,https建立连接时,每次服务端就只返回两层证书了:

image-20231202143535618

其实更好的办法是用openssl工具,因为上面这个方法我发现也不一定准确,我之前确实是发现有返回3层证书(含root ca)的时候,但我写文章这会,测试了下,发现又只有两层了。

但是,用openssl进行如下测试,都是能看到三层证书的:

openssl s_client -debug -connect xxx.com.cn:443 或 [root@VM-0-6-centos ~]# openssl s_client -showcerts -verify 5 -verify_return_error -connect xxx.com.cn:443 CONNECTED(00000003) depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA verify return:1 depth=1 C = US, O = DigiCert Inc, CN = DigiCert Secure Site CN CA G3 verify return:1 depth=0 C = CN, ST = xxxx, CN = *.xxx.com.cn verify return:1 

对我对上述openssl命令,同时抓包的话,包内显示依然只有两层证书,我之前看一本书里也说,一般也是不推荐返回ROOT CA的证书的,没必要:

image-20231202152459708

遗留问题#

因为问题解决了,也就没有再去找负责xxx.com.cn网络接入的同事查问题了,大家事情也多,就这样吧,事情搞定就行了。

但这也算隐形的坑,我猜测的话,可能是一个链路走了waf,一个链路没走waf;所以最终一个协商出用tls v1.2,一个协商出用tls v1.3.

补充问题#

我翻到一个8月份的抓包文件:跟随追踪.pcap,里面的话,服务端确实是返回了3层证书的,包括了ROOT CA的,如下:

image-20231202153427056

所以,我现在也有点疑问了,到底他么该返回几层呢,只能说,如果大家遇到这类问题,可以往这个方面试一下,这个https水还是比较深的。

curl知识补充#

平时经常用curl,但遇到https这种时,一般会失败;此时,习惯性加个-k,跳过https证书校验.

-k, --insecure (SSL) This option explicitly allows curl to perform "insecure" SSL connections and transfers. All SSL connections are attempted to be made secure by using the CA certificate bundle installed by default. This makes all connections considered "insecure" fail unless -k, --insecure is used. See this online resource for further details: http://curl.haxx.se/docs/sslcerts.html 
[root@VM-0-6-centos ~]# curl https://www.baidu.com curl: (77) error setting certificate verify locations: CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none [root@VM-0-6-centos ~]# curl https://www.baidu.com -k <!DOCTYPE html> ... 

但是,这次是要解决https的问题,肯定不能跳过了,所以研究了下怎么把root ca装到机器上,我是centos机器,我发现这样就可以了:

root ca文件参考:https://curl.se/docs/caextract.html wget https://curl.se/ca/cacert.pem -k 下载到cacert.pem 然后指定下ca文件: [root@VM-0-6-centos ~]# curl --cacert cacert.pem https://www.baidu.com 

参考文档#

货拉拉SSL证书踩坑之旅 货拉拉SSL证书踩坑之旅

java.security.cert.CertPathValidatorException问题排查过程

如何在java类系统中导入自签名证书以支持https的第三方系统的访问

教大家在nginx中如何接入ldap认证

技术分享 | MySQL : SSL 连接浅析-腾讯云开发者社区-腾讯云

https证书链校验失败

那些年踩过HTTPS的坑(一)—— 证书链

App防抓包的 8 个实践

网安工具 | 使用小黄鸟HttpCanary快速对安卓手机软件流量抓包

Android13使用HttpCanary抓包

TLS原理与实践(三)tls1.3

openssl: man openssl

openssl s_client : man s_client

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1319027.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3的大致使用

<template><div class"login_wrap"><div class"form_wrap"> <!-- 账号输入--> <el-form ref"formRef" :model"user" class"demo-dynamic" > <!--prop要跟属性名称对应-->…

呜呜呜我要拿Go赢他~ 入门,Go的最简单的 Web 服务器!

前言 继续接入上章节的呜呜呜我要拿Go赢他~ 入门,Go的基础语法! 的文章现在要学的是Go的最简单的 Web 服务器! 补充 上章节的基础语法-方法声明与调用 方法声明 四个部分&#xff1a; 关键字 func方法名字&#xff1a;首字母是否大写决定了作用域参数列表&#xff1a;返回…

C++面试宝典第6题:访问数组和联合体元素

题目 阅读下面的代码段,并给出程序的输出。 (1)访问数组元素。 int a[] = {61, 62, 63, 64, 65, 66}; int *p = (int *)(&a + 1); printf("%d, %d\n", *(a + 1), *(p - 1)); (2)访问联合体元素。 union {short i;char x[2]; }a;a.x[0] = 10; a.x[1] = 1; …

Qt/C++音视频开发60-坐标拾取/按下鼠标获取矩形区域/转换到视频源真实坐标

一、前言 通过在通道画面上拾取鼠标按下的坐标&#xff0c;然后鼠标移动&#xff0c;直到松开&#xff0c;根据松开的坐标和按下的坐标&#xff0c;绘制一个矩形区域&#xff0c;作为热点或者需要电子放大的区域&#xff0c;拿到这个坐标区域&#xff0c;用途非常多&#xff0…

UE5 C++(二)— 游戏架构介绍

架构关系如下&#xff1a; 这里只简单描述下&#xff0c;具体的查看官方文档 AGameMode: AGameMode 是 AGameModeBase 的子类&#xff0c;拥有一些额外的功能支持多人游戏和旧行为。 所有新建项目默认使用 AGameModeBase。 如果需要此额外行为&#xff0c;可切换到从 AGameM…

【LangChain学习之旅】—(3) LangChain快速构建本地知识库的智能问答系统

【LangChain学习之旅】—&#xff08;3&#xff09; LangChain快速构建本地知识库的智能问答系统 项目及实现框架开发框架核心实现机制数据准备及加载加载文本文本的分割向量数据库存储文本的“嵌入”概念向量数据库概念 相关信息获取RetrievalQA生成回答并展示示例小结 Refere…

云服务器部署vue/node项目

此处以阿里云服务器为例&#xff0c;配置的是LNMP环境 vue部署云服务器&#xff1a; 以阿里云服务为例&#xff0c;端口自定义99 1、在 /usr/share/nginx/html/ 该目录下新建文件夹&#xff0c;该文件夹是部署的打好包的前端项目 例&#xff1a; 2、进入nginx目录配置相关配…

【Qt开发流程】之TCP

概述 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输协议。它是互联网协议套件中的一部分&#xff0c;用于在网络上可靠地传输数据。 TCP通过建立连接、数据传输和连接终止三个阶段来进行通信…

音频I2S

前言 基于网上资料对相关概念做整理汇总&#xff0c;部分内容引用自文后文章。 学习目标&#xff1a;简单了解相关概念、相关协议。 1 概述 数字音频接口DAI&#xff0c;即Digital Audio Interfaces&#xff0c;顾名思义&#xff0c;DAI表示在板级或板间传输数字音频信…

ELK(八)—Metricbeat部署

目录 介绍修改配置文件启动 Modulenginx开启状态查询配置Nginx module查看是否配置成功 介绍 Metricbeat 是一个轻量级的开源度量数据收集器&#xff0c;用于监控系统和服务。它由 Elastic 公司开发&#xff0c;并作为 Elastic Stack&#xff08;Elasticsearch、Logstash、Kiba…

Ubuntu18.04安装ffmpeg

前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_C…

解决:AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’

解决&#xff1a;AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’ 文章目录 解决&#xff1a;AttributeError: module scipy.misc has no attribute imsave背景报错问题报错翻译报错位置代码报错原因解决方法方法一 scipy版本回退&#xff08;不推荐&#…

【物联网】EMQX(二)——docker快速搭建EMQX 和 MQTTX客户端使用

一、前言 在上一篇文章中&#xff0c;小编向大家介绍了物联网必然会用到的消息服务器EMQ&#xff0c;相信大家也对EMQ有了一定的了解&#xff0c;那么接下来&#xff0c;小编从这篇文章正式开始展开对EMQ的学习教程&#xff0c;本章节来记录一下如何对EMQ进行安装。 二、使用…

P2P如何使用register_attention_control为UNet的CrossAttention关联AttentionStore

上次的调试到这里了&#xff0c;写完这篇接着看&#xff0c;prepare_latents_ddim_inverted 如何预计算 inversion latents&#xff1a; /home/pgao/yue/FateZero/video_diffusion/pipelines/p2p_ddim_spatial_temporal.py 1. 原始的UNet3D的CrossAttention和SparseCausalAtte…

展示一段比较简单的人工智能自动做模型的程序

人工智能是一种模拟或模仿人类智能的技术。它通过使计算机系统具有一定的认知能力和学习能力&#xff0c;使其能够自动完成一系列复杂的任务。人工智能可以在各个领域应用&#xff0c;包括图像识别、语音识别、自然语言处理、机器学习等。人工智能还可以用于解决各种问题&#…

地平线前端实习一面复盘(加深对var的理解+展开运算符+平拍数组)

目录 前言一&#xff0c;var的作用二&#xff0c;展开运算符三&#xff0c;平拍数组总结 前言 地平线的面试&#xff0c;有提示&#xff0c;很专业&#xff0c;体验很好。 可惜后面未收到消息&#xff0c;但还是要做复盘。收获还是很大的。 一&#xff0c;var的作用 且看下…

30. 深度学习进阶 - 池化

Hi&#xff0c;你好。我是茶桁。 上一节课&#xff0c;我们详细的学习了卷积的原理&#xff0c;在这个过程中给大家讲了一个比较重要的概念&#xff0c;叫做input channel&#xff0c;和output channel。 当然现在不需要直接去实现, 卷积的原理PyTorch、或者TensorFlow什么的…

Python tkinter 初探Toplevel控件搭建父子窗口

目录 Toplevel控件搭建父子窗口 最简明的父子窗口框架 改进一&#xff1a;屏蔽和开放按钮 改进二&#xff1a;子窗口始终在主窗口之上 改进三&#xff1a;增加子窗口的关闭协议 改进四&#xff1a;使子窗口长获焦点 总结 Toplevel控件搭建父子窗口 最近&#xff0c;用P…

直播江湖:东方甄选与董宇辉的权力游戏

出品| 大力财经 文 | 魏力 近期&#xff0c;围绕东方甄选的小作文事件引起了广泛关注&#xff0c;有人将其解读为一场巧妙策划的事件营销&#xff0c;然而&#xff0c;舆情的不可控性使得事态逐渐演变为一场复杂的利益博弈。 东方甄选与董宇辉的“蜜月期”可以说是双方互相成就…

【机器学习】梯度下降法:从底层手写实现线性回归

【机器学习】Building-Linear-Regression-from-Scratch 线性回归 Linear Regression0. 数据的导入与相关预处理0.工具函数1. 批量梯度下降法 Batch Gradient Descent2. 小批量梯度下降法 Mini Batch Gradient Descent&#xff08;在批量方面进行了改进&#xff09;3. 自适应梯度…