Mitmproxy Android真机抓包实战:HTTPS证书与常见问题排查 📅 发布时间:2026/9/17 14:32:59 👁 浏览次数: 做 Android 开发和测试的朋友基本都绕不开抓包这件事。排查线上接口异常、分析第三方 SDK 的请求链路、确认某个请求到底带了什么参数甚至逆向研究别人 App 的数据协议都需要一个趁手的抓包工具。Mitmproxy 是我个人用得最顺手的方案原因很直接跨平台、命令行驱动、支持 Python 脚本二次开发对 HTTPS 流量的解密能力也够强。这篇文章就以真机抓包为主线把环境准备、代理配置、证书安装、流量分析以及常见问题排查完整拆一遍适合刚开始学抓包的新手也适合被证书、Tunneling、SSL Pinning 这类细节卡住过的老手。1. 抓包需求与工具选型1.1 抓包的底层原理与 Mitmproxy 的工作机制先说清楚抓包到底在抓什么。正常情况下App 会直接跟服务器建立 TCP 连接双方通过 HTTP 或 HTTPS 协议交换数据。我们要想看到这些数据就得在客户端和服务器之间插一个“中间人”。Mitmproxy 启动后会变成一个本地代理服务我们让手机的流量先发到这台电脑的指定端口上再由它转发给真实的服务器。对 HTTPS 而言Mitmproxy 会动态生成一张以目标域名为准的证书先跟 App 完成一次 TLS 握手再拿着真实请求去跟服务器建立另一条 TLS 连接。这样一来两端的数据对它来说都是透明的。如果你用过 Wireshark 那种网卡抓包就会明白代理抓包和网卡抓包是两种思路。Wireshark 抓的是网卡上流经的所有数据包能看 TCP 握手、重传、DNS 查询这些底层细节但碰到 HTTPS 只能看到一堆密文。Mitmproxy 工作在应用层它关注的不是每一个数据包而是完整的请求和响应甚至可以直接修改请求体再放行。日常调试接口、定位参数错误、检查返回字段Mitmproxy 的效率明显更高。1.2 为什么不用 Fiddler 或 Charles网上教程里 Fiddler 和 Charles 的出镜率很高它们确实各有优点。Fiddler 在 Windows 生态里集成度高界面直观Charles 的 UI 做得漂亮在 macOS 上很流行很多前端同学习惯用它看 HTTPS 请求。但真机抓包场景下我仍然首选 Mitmproxy原因有这么几个Mitmproxy 是纯命令行工具对内存和 CPU 的占用比 Java 系的抓包工具低一个量级长时间挂机抓包不容易卡。它自带 mitmweb 的 Web 界面既保留了命令行的高效又能像 Charles 一样点开看请求详情一举两得。脚本扩展能力强Python 里写一个 addon 就能实现自动保存、自动改包、按域名过滤这是 Fiddler 的 FiddlerScript 做不到的灵活度。跨平台一致性好Windows、macOS、Linux 上行为完全一致团队协作时不会出现“我本地能抓你本地不行”的尴尬。当然如果你只是临时看一眼某个请求Charles 的 GUI 确实更友好。但如果你需要持续调试、反复验证、批量处理流量Mitmproxy 的效率和自动化能力会让 Fiddler 和 Charles 显得笨重。1.3 真机抓包的适用场景与边界这篇文章讲的是 Android 真机抓包和模拟器抓包有几个明显的差异。模拟器天然共享宿主机的网络代理配置非常方便但很多 App 会检测模拟器环境直接拒绝运行或者屏蔽关键功能。真机更贴近真实用户环境能验证 GPS、相机、传感器、微信登录这类依赖硬件的功能但因为 Android 版本碎片化严重证书信任策略、代理行为差异很大坑也更多。Mitmproxy 也不是万能的。它处理 HTTP、HTTPS、WebSocket 这类应用层协议很顺手可如果你要抓的是游戏里的私有 TCP/UDP 协议或者想看 TLS 握手细节那还是得用 Wireshark。还有一类 App 做了 SSL Pinning把服务器证书固定写在代码里不信任系统证书这种情况下直接装 Mitmproxy 证书也没用需要配合绕过方案后面第 6 章我会专门展开讲。2. Mitmproxy 部署与启动方式2.1 环境准备与安装Mitmproxy 的安装非常省事。如果你的电脑上有 Python 环境一条命令就能搞定pip install mitmproxymacOS 用户也可以用 Homebrew 安装brew install mitmproxy安装完成后在终端输入mitmproxy --version确认版本。老版本和新版本的语法差异不小网上的教程很多写得比较早如果你照着敲命令报错先看一下版本号尽量用 10.x 以上的版本。Windows 用户需要注意的是Mitmproxy 依赖 Python 的 asyncio 事件循环建议直接用官方推荐的安装方式别在旧版 Python 2.7 环境里折腾。装完以后把 Python 的 Scripts 目录加到系统 PATH不然命令行里找不到 mitmproxy。2.2 三种启动模式怎么选Mitmproxy 安装后会自动注册三个命令分别是mitmproxy、mitmdump和mitmweb。它们底层逻辑完全一样区别只在操作界面上mitmproxy终端交互界面支持键盘快捷键操作适合在服务器或者纯命令行环境里实时看流量。mitmdump无界面模式流量会直接打印到终端适合跑脚本、做自动化抓包也适合把输出重定向到日志文件。mitmweb自带一个 Web 界面浏览器打开后可以点选查看请求和响应对新手最友好。如果你是在自己电脑上做日常调试我的建议是先开mitmweb因为它的展示形式最直观请求列表、请求头、响应体、Cookie 全都能点开看不需要记快捷键。等熟悉了以后再用mitmdump配合脚本做自动化处理。三个命令默认监听 8080 端口如果想换端口用-p参数指定比如mitmweb -p 88882.3 把流量保存下来回放分析抓包过程中经常遇到这样的情况流量抓到了但当时没来得及细看回头想分析却发现会话没了。Mitmproxy 贴心地提供了流量落盘功能启动时加上-w参数就能把全部流量写入文件。mitmdump -w capture.flow抓完以后用mitmproxy -r capture.flow或者mitmweb -r capture.flow就能重新打开历史会话翻看之前的请求。这个功能在做长时间抓包时特别有用比如想统计一个 App 启动后半小时内调了哪些接口、每个接口的耗时分布把整个会话存下来再统一分析就行。提示-w和-r组合使用可以让终端只输出过滤后的内容原始流量完整落盘。比如一边实时打印图片类请求一边把所有流量存文件这样排查问题的时候两不耽误。3. 真机连接代理配置的两种可靠方案3.1 方案AWiFi 局域网代理最常见的真机抓包方式是把手机和电脑连到同一个 WiFi 下然后在手机 WiFi 设置里手动配置代理。具体操作步骤是这样的电脑终端输入ipconfigWindows或ifconfigmacOS/Linux找到当前网卡的 IP 地址比如192.168.1.100。然后在手机上打开“设置 - WLAN”长按当前连接的 WiFi 选择“修改网络”把代理模式从“无”改成“手动”主机名填电脑 IP端口填 8080保存即可。这个方案胜在简单手机和电脑只要在同一网段就能用。但它有明显的短板代理走 WiFi信号不好或者路由器开启了 AP 隔离流量就传不到电脑上。另外部分 App 在启动时会检测系统代理设置发现代理异常直接拒绝联网比如很多银行的 App、支付类 App 都会有这种保护机制。遇到这种 AppWiFi 代理方案往往会直接失败。3.2 方案BUSB 代理推荐USB 代理的核心思路是手机通过 USB 线连电脑用 adb 工具做端口转发把手机上的 8080 端口转发到电脑上的 8080 端口然后在手机里把代理地址设置为127.0.0.1:8080。因为代理指向的是本机回环地址App 检测不到所谓的“外部代理”成功率比 WiFi 代理高很多。具体操作分三步。第一步手机开启 USB 调试模式在“开发者选项”里打开“USB 调试”用 USB 线连上电脑终端输入adb devices确认设备已被识别。第二步执行端口转发命令adb reverse tcp:8080 tcp:8080这条命令的意思是手机上访问127.0.0.1:8080时流量会被转发到电脑本地的 8080 端口。第三步在手机 WiFi 设置里把代理地址改成127.0.0.1端口填 8080。注意即使用 USB 代理手机的 WiFi 仍然要保持开启因为 Android 系统需要 WiFi 网络来触发网络配置只是数据流量不再走 WiFi 而是走了 USB 通道。我实测下来USB 代理的稳定性比 WiFi 代理好得多。WiFi 代理模式下偶尔会出现请求断流、响应超时的情况USB 代理几乎没有这个问题而且因为不经路由器转发局域网内其他人的网络行为也不会干扰抓包。如果你要长时间跑一个自动化测试或者批量抓包强烈建议优先考虑这个方案。3.3 代理配置后的连通性自检配置完代理不要急着打开目标 App先做一次连通性测试。手机浏览器访问http://mitm.it如果代理配置正确页面会正常打开。如果打不开按优先级排查三件事电脑上的 mitmproxy 有没有启动端口是不是 8080。手机的代理 IP 和端口是否填对错误 IP 是最常见的翻车原因。Windows 防火墙有没有拦截 8080 端口的入站连接macOS 则要检查“允许传入连接”的设置。提示手机和电脑都不在同一个网段时WiFi 代理基本连不上电脑 IP 建议固定别用 DHCP 分配的地址不然路由器重启后 IP 变了代理就失效了。4. HTTPS 证书安装与 Android 版本适配4.1 证书下载与安装步骤HTTP 流量配好代理就能直接抓但 HTTPS 流量如果不装 Mitmproxy 的根证书看到的只是一堆加密乱码或者干脆显示 CONNECT 隧道。证书安装是 HTTPS 抓包里最核心、也最容易出问题的环节。代理配置成功后手机浏览器访问http://mitm.it页面上会列出各种平台选择 Android 下载证书。下载完成后去“设置 - 安全 - 加密与凭据 - 安装证书”选择刚才下载的 CA 证书文件。不同 Android 版本的入口名称不完全一样但基本都在“安全”或“安全性与位置信息”之类的菜单下面。安装完成后在“信任的凭据 - 用户”标签页里能看到一个名为mitmproxy的证书说明安装成功。这时候再打开目标 AppMitmproxy 就能解密 HTTPS 流量了。4.2 Android 7.0 后抓不到 HTTPS 的根源很多人在这一步卡住证书装了mitm.it也能打开但抓自己的 App 时还是只有 CONNECT 记录看不到具体请求内容。问题多半出在 Android 7.0API 24以后的证书信任策略变化上。Android 7.0 之前App 默认信任用户证书装了证书就能抓。Android 7.0 之后系统默认只信任系统证书区安装在“用户”标签页里的证书对大多数 App 无效。也就是说不是你证书没装对而是 App 压根就不认你装的证书。那为什么浏览器能抓到呢因为浏览器自带了一套网络栈会主动信任用户证书而大多数 App 用的是 OkHttp 这类网络库走的是系统证书校验用户证书默认不参与校验。这也是网上很多教程只讲“装证书”却让无数人翻车的根本原因。4.3 通过网络安全配置信任用户证书针对 Android 7.0 及以上的版本最正统的解决方式是在 App 里配置网络安全策略。在res/xml/目录下新建一个network_security_config.xml内容如下?xml version1.0 encodingutf-8? network-security-config base-config trust-anchors certificates srcuser / certificates srcsystem / /trust-anchors /base-config /network-security-config然后在 AndroidManifest.xml 的 application 节点里引用这份配置application android:networkSecurityConfigxml/network_security_config ...特别注意这个方案只对 debug 包和可修改代码的工程有效。如果是你开发的 App加完配置重新打包安装就能抓 HTTPS如果是别人的 Release 包没有源码没法改配置就需要配合第 4.4 节的方案或者绕过 SSL Pinning。4.4 Debug 包与系统证书区的特殊处理没有源码、又想抓 Release 包的 HTTPS只能从设备层面想办法。Android 系统在启动时会加载/system/etc/security/cacerts/目录下的系统证书如果把 Mitmproxy 的证书也放进去App 就会信任它。但在普通零售版手机上系统分区是只读的需要先解锁 bootloader 或者拿到 root 权限才能写入。实际操作时很多人选择用 user-debug 版本俗称“水货”或“开发版”固件的设备来处理。这类设备的 adb root 权限和 system 分区写入权限是开放的抓包前把证书转换成系统证书格式push 到/system/etc/security/cacerts/并改好权限即可。证书文件名必须是证书主题的 Hash 值加.0后缀很多人在这里卡住因为文件名算错或者权限不对系统直接不认。如果你手头没有这类设备还有一个实用技巧用模拟器配合。Android 模拟器的系统镜像可以选择“可写系统”启动后用adb root拿到权限再对系统分区进行操作。模拟器抓包有一个天然优势就是网络环境干净、可以随意重置快照但缺点也很明显部分 App 会检测模拟器特征直接不允许运行。所以一般我会建议客户准备一台专用的 user-debug 或 root 设备专门用来抓包好用且省心。5. 开始抓包流量观察与分析技巧5.1 用 mitmweb 快速定位请求证书装好、代理配置完成后启动mitmweb浏览器会自动打开http://127.0.0.1:8081的界面。这个时候用手机操作目标 App界面里会实时刷出所有经过代理的 HTTP 和 HTTPS 请求。mitmweb 的界面左侧是请求列表每一行会显示请求方法、域名、路径、状态码和耗时。点开任意一条请求上面会分 tab 展示 Request、Response、Detail 等信息。Request 里有完整的 URL、请求头、请求体Response 里有状态码、响应头和响应体。对排查问题来说这几个 tab 已经包含了 90% 的信息量。如果你要观察的接口返回的是 JSONmitmweb 会自动把响应体格式化成可折叠的树形结构不用再复制到别的工具里格式化。这一点在实际联调时特别有用接口返回字段名对不上、类型不对、某个字段为 null一眼就能看出来。5.2 过滤规则与常用操作流量多的时候光靠肉眼在列表里翻找肯定不现实。mitmweb 顶部有一个过滤框支持按域名、URL、HTTP 方法、状态码等条件过滤。比如只看指定域名的请求~d api.example.com只看 POST 请求~m POST只看返回 500 的请求~c 500如果你用的是终端版mitmproxy记住几个最常用的快捷键e编辑当前请求、r重放请求、a添加快捷键、q返回。实际操作时我经常在 mitmweb 里看总体流量在终端版里做编辑和重放两边配合。提示过滤规则里的~d和~u要区分清楚。~d匹配域名~u匹配完整的 URL 字符串。如果只是想筛某个 host 下的请求用~d更准确。5.3 断点修改响应做联调测试Mitmproxy 最强大的能力是不仅能看还能改。开发过程中经常需要模拟各种异常情况比如接口超时、返回空数据、字段值异常。这些场景在真实环境里很难复现但用 Mitmproxy 的断点功能可以轻松做到。在mitmproxy终端界面里先对指定请求设置拦截条件~d api.example.com然后按i键输入拦截规则。当流量经过时Mitmproxy 会暂停在终端界面按e编辑请求或响应内容按a确认放行。比如把某个优惠券接口的discount字段从10改成100再放行App 里就会看到修改后的数据。如果你觉得交互式操作不方便还可以写一个 Python addon 自动修改。下面这个脚本会把所有响应里的success: false改成success: truefrom mitmproxy import http def response(flow: http.HTTPFlow) - None: if example.com in flow.request.pretty_host: text flow.response.get_text() if text: flow.response.set_text(text.replace(success: false, success: true))保存为modify.py启动时加载即可mitmproxy -s modify.py这种自动化改包的能力在测试 App 边界条件时能省下大量时间也是 Mitmproxy 区别于 Fiddler 和 Charles 的最核心优势。6. 真机抓包常见错误与排查实录6.1 问题速查表真机抓包的坑比较集中我直接把这些年踩过的问题整理成一张速查表大家对照排查即可。问题现象常见原因解决办法抓不到任何请求手机代理没配好或没生效重新配置代理检查 IP 和端口只有 CONNECT 隧道没有具体请求内容HTTPS 证书未被 App 信任安装证书配置 network_security_config 或系统证书App 提示“连接不安全”或证书无效证书未安装或系统时间不对重新安装证书校准手机时间App 启动就报网络异常应用做了 SSL Pinning配合脚本绕过 Pinning或用调试版覆盖浏览器能抓App 抓不到Android 7.0 默认不信任用户证书在代码里信任用户证书或放入系统证书区WiFi 代理下请求超时路由器 AP 隔离或信号差改用 USB 代理方式443 端口被占用其他程序占用了 mitmproxy 端口更换监听端口-p 8888手机连上代理后所有 App 都无法联网代理地址填写错误核对电脑 IP确认端口未被防火墙拦截6.2 大量 Tunneling 却没有解密流量这是新手最常问的一个问题mitmproxy 界面里全是CONNECT开头的记录俗称 Tunneling可就是看不到 GET、POST 这些具体请求。看起来像是流量通了但数据全是黑的。出现这种情况的原因很简单客户端通过代理建立了 TLS 隧道但没有信任 Mitmproxy 的证书。Tunneling 请求本身只是 CONNECT 方法它负责在客户端和目标服务器之间建立一条通道真正的 HTTP 内容都在隧道里面。证书不生效时Mitmproxy 只能看到隧道建立成功看不到隧道内部的数据。处理思路还是回到证书上。先确认手机有没有安装 mitmproxy 的 CA 证书再确认目标 App 是否信任用户证书。如果 App 不信任就用第 4.3 节的 network_security_config 方案或者把证书放进系统证书区。把证书问题解决掉Tunneling 就会自动变成可读的 HTTP 请求。6.3 App 提示“上传失败”或“网络请求错误”真机调试过程中偶尔会遇到 App 报“上传失败网络请求错误”之类的提示。这种问题不一定是抓包工具造成的但抓包时确实更容易触发。常见的情况是上传接口走了 HTTPS而 App 对上传域名做了单独的证书校验也就是常说的多域名证书绑定。Mitmproxy 的证书只在部分域名上被信任其他域名直接校验失败。看到这种报错第一时间去 mitmweb 里看对应的请求记录如果发现有请求的状态码是 400 或者 TLS 握手失败基本可以断定是证书问题。还有一种情况是 App 用content://协议读取文件内容比如微信、百度等 App 在真机调试时通过 FileProvider 分享文件如果代理环境导致传输中断上传请求同样会报错。这种问题跟抓包本身关系不大更多是设备环境和代理共同作用的结果。建议先停掉代理确认 App 能正常上传再重新开启抓包。6.4 微信小程序真机调试请求无法到达后端小程序真机调试时经常出现“请求无法到达后端”的问题。这里先纠正一个误区小程序的网络请求不走系统代理而是走微信自己封装的那套网络逻辑。你按照普通 App 的方式给手机配代理大概率什么都抓不到。想抓小程序的包有两个办法。第一个办法是在微信开发者工具里开启“真机调试”模式在这个模式下小程序的请求会经过开发者工具转发配合代理工具就能看到流量。第二个办法是处理域名白名单问题小程序要求所有请求域名必须在小程序后台配置过如果没有配置或者代理转发了未备案的测试域名请求会被拦截。如果你遇到“请求无法到达后端”的报错先在 mitmweb 里看有没有对应的请求记录。如果有记录说明请求发出来了问题出在后端返回如果没有记录说明小程序请求被拦截在更早的环节需要检查域名白名单和开发者工具配置。别一上来就怀疑代理和证书很多情况下是业务配置问题。6.5 代理配置正确但部分请求直接超时代理配好了证书也装了大多数请求都能正常抓到但个别接口就是超时。这种情况我在办公环境里遇到过很多次原因主要出在 HTTP 代理的Keep-Alive连接上。某些服务器对长连接的管理比较严格代理中转后连接复用机制会出现错乱表现为第一批请求正常后续请求挂起直到超时。解决办法分两步第一步在 mitmproxy 里设置连接复用超时参数或者干脆禁用连接复用mitmweb --set connection_strategylazy第二步改造 App 端的网络配置把连接池的keepAlive时间调短。如果 App 是 OkHttp 实现的可以在OkHttpClient里指定OkHttpClient client new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build();这样既不会影响正常业务又能避开代理环境下的连接复用坑。写在最后抓包这件事工具只占一半另一半是对网络协议和客户端行为的理解。遇到问题别急着换工具先想清楚流量是在哪个环节断掉的是代理没生效还是证书没被信任或者是 App 做了额外的校验。多抓几次、多踩几次坑你对 Android 网络栈的理解会比看一百篇教程都深刻。尤其是 Tunneling、SSL Pinning、用户证书和系统证书这些概念看起来枯燥但只要你亲手在真机上解决过一次后面的路就顺了。