资讯动态

Android 7.0+ HTTPS抓包:Charles证书信任与网络安全配置实战

发布时间:2026/10/21 18:34:42 来源:尧图企业网站定制
做过几年Android开发的人对Charles应该都不陌生。它本质上是一个本地调试代理手机把流量指到它那里它负责转发、解密、展示就这么一个简单循环能帮我们解决大量接口联调问题。但这个工具在Android 7.0之前是“装个证书就行了”7.0之后就开始变得有点讲究很多新手第一把就直接挂在证书信任这一步打开App只能看到一串CONNECT请求体完全看不到第一反应通常是“是不是我装证书装错了”。这篇文章就是专门聊这个问题的。我会先讲清楚Android 7.0到底改了什么东西再给一套已经在多个项目里验证过的Charles配置方案重点放在“自己开发的App怎么配置才能正常解密HTTPS”这条主线上。文末还有一份高频问题速查表都是我自己在实操中踩过的坑适合刚接手App联调、被证书问题卡住的人直接抄作业。1. 为什么Android 7.0让Charles突然“失灵”了1.1 你大概也遇到过这种场面先把场景还原一下。手机连上Wi-Fi设置里把代理指向电脑的局域网IPCharles端口8888一切看起来都很正常。Charles界面上也确实能看到来自手机的连接但打开自己App里某个页面列表里只出现一条条CONNECT api.example.com:443双击从下方详情面板看HTTP报文区域是空的或者只有一行“No response data found”。如果你此时去浏览器里访问一个HTTPS网站浏览器会提示证书不受信任——和你在测试环境里遇到的现象差不多。这个“忽好忽坏”的体验最容易让人怀疑Charles本身有问题于是重装证书、重启Charles、甚至重刷手机一通折腾下来往往还是老样子。问题不在工具而在Android系统对证书信任层次的管理方式变了。升级到Android 7.0API 24以后系统默认不允许App信任“用户证书”只有预置在系统分区里的“系统证书”才会被默认认可。而Charles安装到手机上时默认是作为用户证书存在的所以App根本不买账。1.2 证书信任机制为什么一个是用户级一个是系统级证书类型全称存储位置是否被App默认信任系统证书System CA/system/etc/security/cacerts是用户证书User CA/data/misc/user/0/keystore 或相关区域Android 7.0默认否Android 7.0之前App对证书的信任判断比较宽松用户区和系统区的证书都能用。7.0之后系统开始收紧判断基准变成“targetSdkVersion”当App的targetSdkVersion不低于24时默认只信任系统证书。我们日常开发用的App大多已经把targetSdk升到30甚至更高了所以这个变化几乎影响到了所有正在维护中的项目。可能有人会问为什么Google要做这个改动因为把证书证书安装到用户区只需要锁屏密码或生物识别攻击者一旦拿到你解锁后的手机也能顺手装一个他们自己的根证书然后就能解密这台设备上任何不额外做校验的HTTPS流量。把用户证书从默认信任圈里剔除能明显抬高这种攻击的门槛。1.3 动手前先想清楚你处在哪条技术路线上不同的抓包需求对方案的要求完全不一样我先帮你把路线理一下调试自己开发的App这是最常见的情况。你手里有源码可以通过修改工程配置让App信任Charles的证书推荐使用Android官方的网络安全配置这也是本文要重点讲的方案。调试某个需要授权的后台服务或内部工具如果这个工具的包名是你们自己维护的同样走官方配置即可。查看第三方App的网络请求在这里我必须多说一句没有厂商授权的情况下抓包、绕过证书校验去读别人的App流量既涉及隐私合规问题也可能违反相关使用条款。这种场景在技术社区里经常被讨论但它不应该出现在“开发调试”的范畴里我更建议采用正规的联调协作流程而不是在设备上做文章。把路线分清楚之后你会发现真正值得花精力掌握的其实只有“自己App 官方网络安全配置”这一套。2. 跑通基础环境Charles与手机的首次握手2.1 Charles端三个必须检查的地方在动手机之前先把电脑上的Charles调校好。很多人证书装了一百遍没效果回头看是Charles这边的SSL代理压根没开。第一步确认代理端口。打开Proxy Settings默认端口是8888如果你的电脑上还有其他程序占用这个端口改成8080或别的可用端口都行。自己改过的端口要记住后面手机填代理地址时要用同一个。第二步也是最容易被漏掉的一步Proxy Settings里的“SSL Proxying”配置。很多教程会让新手勾选“Enable SSL Proxying”就算完但光勾上还不行需要在SSL Proxying Settings里添加要解密的主机规则。最粗暴但也最实用的填法是*:443意思是解密所有走443端口的请求。在初期排查问题阶段我建议就用这个通配规则先把问题跑通再收窄范围。第三步检查电脑防火墙。这么个场景经常碰到手机设置好了代理Charles页面里就是看不到任何连接折腾半天发现是电脑防火墙拦截了局域网入站请求。Windows上如果弹出“允许Charles进行通信”的提示务必勾选专用网络macOS如果网络权限被拒绝需要去系统设置里给Charles放行。注意Charles监听的是本机所有网卡的8888端口这意味着跟你同一局域网的其他设备都能把代理指向这里。如果这台电脑连接在办公网里用完记得把代理关闭或限制监听地址避免无关流量全部经过你的电脑。2.2 手机端代理设置先把手机和电脑连到同一个Wi-Fi这一步看着简单实际翻车率极高。很多办公室网络是AP隔离的或者访客网络允许上网但不能互访手机和电脑看似都在同一路由器下面实际上并不互通。判断方法很简单手机上打开浏览器输入http://电脑的局域网IP:8888如果能看到一个类似Charles的提示页说明网络互通正常。代理配置路径随Android版本不同略有差异但逻辑一致进入当前Wi-Fi的属性 → 代理设置 → 手动代理 → 主机名填电脑的局域网IP、端口填8888。保存后Charles里应该立刻出现一条来自手机的新连接。这里还要提醒一句部分手机在“叠加代理”时会出问题例如系统自带的网络加速功能、双Wi-Fi加速等。这些功能开启时本机的基础网络权限直接绕过代理导致Charles看不到流量。遇到这种情况先把这些网络增强功能关掉再测试抓包链路。2.3 验证基础链路是否打通手机代理配好后随便点开几个AppCharles里应该有HTTP请求或者CONNECT记录。如果只有CONNECT而看不到HTTP内容这是正常的——因为HTTPS流量目前还没有被解密Charles只是帮忙建立了隧道。到这一步基础代理链路就算打通了。接下来才是本文的重头戏怎么让App在Android 7.0上信任Charles的证书把隧道里的明文内容还原出来。3. 自己App的进阶配置网络安全配置实战3.1 官方方案的核心思想解决“App不信任用户证书”的问题官方给出的标准方案是网络安全配置。它的本质是允许你在App里声明“我要信任哪些证书来源”声明方式是一份XML配置打包时编译进App。对于调试场景核心配置就一句话在默认信任锚里加上user来源。?xml version1.0 encodingutf-8? network-security-config base-config cleartextTrafficPermittedtrue trust-anchors certificates srcsystem / certificates srcuser / /trust-anchors /base-config /network-security-config这段配置的作用是让App对“所有域名的HTTPS请求”都同时信任系统证书和用户证书。Charles的根证书装在用户区之后就能被这个App接受了。3.2 分环境配置别把调试配置带进线上包如果你直接把上面这份XML放到main源码集里等于让正式版App也信任了用户证书这不算是一个好实践。从安全角度考虑正式版应当维持系统证书的默认信任策略只在调试包中放行。推荐的工程实践是分源码集管理把信任用户证书的XML放在src/debug/res/xml/目录下正式版单独放一个不包含user来源的XML。Gradle构建时会自动根据构建变体选择对应的资源覆盖。Manifest中的引用可以统一写application android:networkSecurityConfigxml/network_security_config ... 同一份资源名在debug和release分别解析到不同内容这种覆盖机制在Android资源合并里很常见比用BuildConfig判断再动态改配置要干净得多。另外有个容易漏掉的细节Android 7.0对cleartextTrafficPermitted的默认值很严格。targetSdk 28以上默认禁止明文HTTP流量。如果你调试的是非HTTPS的本地接口比如http://192.168.1.100:8080光改证书配置不够还要在base-config里把cleartextTrafficPermitted设为true或者用domain-config针对内网域名单独放行。上面这份XML里已经带上了开发期直接复制过去就行。3.3 只想让特定域名信任用户证书怎么办如果不想放开所有域名的信任范围可以用domain-config做更细的控制?xml version1.0 encodingutf-8? network-security-config domain-config cleartextTrafficPermittedtrue domain includeSubdomainstrueapi.example.com/domain trust-anchors certificates srcsystem / certificates srcuser / /trust-anchors /domain-config /network-security-config这样配置的效果是只有api.example.com及其子域名的HTTPS请求会信任用户证书其他域名维持系统默认策略。对于只调试某个特定后端服务的项目这种收窄配置反而更贴合需求线上包即使误用了这份配置暴露面也小得多。3.4 如果你手里的工程用了证书固定不少团队会在客户端里对后端证书做固定校验协议上叫Certificate Pinning。判断方法很简单在Charles能解密请求的前提下看App是否依然报SSL错误。如果报错大概率是有固定逻辑常见做法是把指纹写死在代码里或者用OkHttp的CertificatePinner。处理证书固定没有官方“一键解决”的说法。最干净的做法是在调试配置里提供一个独立的OkHttp实例跳过固定逻辑如果固定的是公钥而不是证书链也可以把Charles证书的对应公钥指纹临时加进白名单。需要提醒的是这类改动务必限制在debug版或专门的调试入口里不要混入发布构建。4. 证书安装与一次完整的HTTPS抓包4.1 生成并导出Charles根证书做好上面的工程配置后接下来安装证书。打开Charles从顶部菜单Help→SSL Proxying→Install Charles Root Certificate桌面上会弹出一个根证书的下载窗口。这个弹窗里的按钮是给电脑浏览器用的手机端不需要从这里安装。手机端最省事的方式是让手机自带浏览器访问http://chls.pro/ssl。注意这里用的是HTTP协议它的作用就是下载一个名为getssl的PEM证书文件。下载完成后系统会弹出“安装证书”的向导跟着提示走即可。某些定制系统第一次安装CA证书时会提示先设置锁屏密码这不是错误是Android出于安全考虑做的强制要求。安装走完流程后要去系统设置里确认一下证书确实存在。路径一般是“设置 → 安全 → 加密与凭据 → 信任的凭据”切到“用户”标签页能看到一条以“Charles Proxy CA”开头的记录。4.2 小细节证书有效期太长的经典报错新版Android系统在安装CA证书时会校验证书有效期。Charles默认生成的根证书有效期较长部分系统会弹出“证书无效”或直接提示安装失败。解决方法是给Charles换个短有效期的根证书。在Charles里执行Help→SSL Proxying→Reset Charles Root Certificate重置过程中会询问有效期选项选择短周期比如一年。重置后重新走一遍chls.pro/ssl下载安装即可。这里涉及一个关键点升级证书之后手机上旧的Charles证书最好先在“用户凭据”里删掉否则新旧两个根证书同时存在反而容易引发“到底信任了哪一个”的混乱。4.3 完整抓一次HTTPS请求的步骤按下面的顺序操作第一次解密成功基本没有悬念收集证书。手机上装好Charles根证书。检查SSL Proxying。确认SSL Proxying Settings里已有*:443或目标域名规则。手机设代理确认Charles里能收到CONNECT记录。打开你配置过网络安全配置的App随便触发一个HTTPS请求。回到Charles找到对应主机点击它展开上方的请求/响应面板。正常现象下请求面板里能看到URL、请求头、请求体响应面板里能看到返回的JSON或页面内容。如果看到的是乱码或“Secure Black Box”多半是证书装入用户区后没有被App信任或者SSL Proxy规则没覆盖到。我一般习惯在Charles里给请求列表加两列一列是Host一列是Status方便快速识别哪台主机还在失败。做联调的时候看到某个接口Status一直挂着红色叉号就能直接定位到是SSL层还是应用层的问题。提示抓到的HTTPS包在Charles界面里是以明文展示的但发送到目标服务器时仍然是标准加密握手服务器侧不会感知到中间代理解密过程。这意味着你拿到的既是明文分析数据也保留了真实传输状态这是Charles做协议调试最顺手的地方。5. 高频问题与排查技巧实录5.1 问题速查表现象可能原因处理方式只有CONNECT看不到HTTP内容SSL Proxying未开启或主机规则缺失在SSL Proxying Settings添加*:443并勾选Enable界面提示Trust anchor not foundApp未信任用户证书配置网络安全配置见第3节证书安装失败/提示无效Charles证书有效期过长Reset Charles Root Certificate后选短有效期App内请求超时、持续转圈手机与电脑不在同一网段用浏览器访问http://电脑IP:8888验证连通性只有部分App能抓到明文目标App也做了证书固定在调试分支里移除或放行固定逻辑捕获到的JSON显示乱码压测数据被压缩在Charles里响应体右键选择解压或检查请求是否带了Accept-Encoding5.2 三个容易忽略的坑第一个坑是“代理冲突”。手机上如果装了其他代理服务或网络加速类工具Android的代理设置可能不会真正生效或者说流量被其他通道接管了。有一次我排查了很久最后发现是手机厂商自带的网络加速功能在暗中作祟。遇到抓不到包的情况先把这类功能全部关掉再试。第二个坑是“证书下载域名记错了”。chls.pro/ssl是Charles的固定域名但如果你用手机自带的浏览器打开a域名后又用其他应用内置浏览器收藏了链接部分WebView因为缓存策略可能不会触发下载动作。正解是清除浏览器缓存或者直接换一个浏览器再访问。第三个坑是“签名证书不匹配”。如果你在Charles里重置了根证书必须重新在手机上安装否则旧证书在抓包时会偶发性地出现握手失败。这个问题隐蔽的地方在于它不是每次都失败而是间歇性出现容易让人误以为网速慢或服务端异常。5.3 怎么验证抓到的数据是完整可信的很多时候我们抓包是为了排查“App发出的请求和后端收到的请求不一致”的问题。Charles显示的数据看着很完整但不能直接认定就是真实线路上的数据。我习惯做一步交叉验证在同一个接口上用Postman或curl模拟一样参数的请求对比Charles里抓到的请求体和响应体。再提醒一个联调场景里的实用习惯抓包结束后把Charles里响应面板的JSON复制到本地格式化以后保留一份带时间戳的存档。接口联调时后端同事说“我返回的字段你那边没收到”有存档能少说半小时废话。另外还有一个容易让人困惑的地方Charles默认会对响应做chunked transfer的解码展示时是拼好的完整响应但实际网络上可能是分成多个chunk传的。这在排查下载类接口时要注意——Content-Length的大小、chunk数量这些细节只有看原始流量才能确认。6. 我的一点实操心得Android 7.0的证书信任机制改动对普通开发者的最大影响不是技术上的而是习惯上的。旧办法“装个证书就完事”在7.0之后真的行不通了只有理解了系统证书和用户证书的区别再搭配官方网络安全配置才能在任何一个新机器上快速把调试环境搭起来。我个人现在搭一个新项目抓包环境速度大概稳定在10分钟左右。先改network_security_config.xml放行user证书再让Android构建出debug包然后装Charles证书、配代理、开SSL Proxying。最花时间反而不是证书而是手机厂商各种网络功能的干扰项。如果你配置完成后还是不行别急着质疑Charles先逐条检查代理是否生效、SSL Proxying规则是否匹配、App是否真的走了代理。大概率问题出在这三个环节之一。最后分享一个小技巧把常用的网络安全配置XML存成模板新建项目时直接复用能省掉重复排查的时间。遇到团队里有新人搞不定抓包把模板丢过去基本都能自己解决。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑