mitmproxy能抓HTTPS请求但无法解析响应体,主因是App启用证书锁定(Certificate Pinning),导致TLS握手后断连或返回空body;Android 7+默认不信任用户证书,iOS更严格,需root、越狱或Frida注入绕过。

mitmproxy 能抓到 HTTPS 请求,但默认不解析加密内容;必须装证书、配手机代理、关掉证书锁定(Certificate Pinning),否则看到的全是空响应或连接失败。
为什么 mitmproxy 抓不到 App 的 HTTPS 响应体
不是 mitmproxy 不行,是现代 App 普遍启用证书锁定(Certificate Pinning),它会校验服务端证书是否与预埋的公钥/证书指纹一致。mitmproxy 动态生成的中间人证书必然不匹配,导致 TLS 握手后直接断连或返回空 body。
- 典型现象:
502 Bad Gateway、Connection reset by peer、响应体为空但状态码是200 - Android 7+ 默认不信任用户安装的 CA 证书,需额外将证书放进系统信任库(需 root)或改用
network_security_config临时绕过(仅调试) - iOS 更严格,越狱非必需但能大幅降低绕过难度;未越狱设备需配合 Frida 注入 hook
NSURLSession或AFNetworking相关方法 - mitmdump 脚本里收到的
flow.response.content是 bytes,但若 TLS 已被中断,这里就是None或空字节串
mitmdump 怎么写脚本实时提取 JSON 数据
mitmdump 的核心是重写 response 方法,对符合路径和 Content-Type 的响应做解析。重点不是“能不能”,而是“在哪一层过滤最稳”——优先看 Content-Type: application/json,再结合 URL 关键词(如 /api/、/v1/)。
- 不要依赖
flow.request.url的完整域名判断,App 可能用 IP 直连或 CDN 域名,用 path 匹配更可靠 - 响应解码前先检查
flow.response.headers.get("Content-Encoding"),gzip 压缩需用gzip.decompress()解开 - JSON 解析要用
try/except json.JSONDecodeError包裹,部分接口返回 HTML 错误页但 Content-Type 仍是 JSON - 示例片段:
def response(flow): if "application/json" in flow.response.headers.get("Content-Type", ""): try: data = json.loads(flow.response.content) print("API result:", data.get("data") or data.get("result")) except Exception: pass
手机连 mitmproxy 后打不开 App 或闪退怎么办
这不是网络配置错了,大概率是 App 检测到代理环境或证书异常后主动拒绝运行。常见触发点有三类:代理检测、证书存在性检测、证书锁定失败后的降级行为。
- 安卓上可尝试关闭 WiFi 代理后进 App,再打开代理——有些 App 只在启动时检测代理
- 检查手机系统时间是否准确,误差 >3 分钟会导致 TLS 握手失败,表现为白屏或立即退出
- 某些金融/支付类 App(如支付宝、银行类)会调用
ConnectivityManager.getActiveNetworkInfo()查代理标志位,mitmproxy 无法隐藏,此时必须用 Frida hook 掉检测逻辑 - mitmproxy 启动时加
--set block_global=false防止拦截 DNS 请求,避免部分 App 因 DNS 异常直接崩溃
抓到的数据怎么导出成结构化格式
别在 mitmdump 里直接写文件 IO,高并发下容易丢数据或损坏 JSON。推荐用队列 + 单独线程落盘,或者用 mitmweb 界面手动导出 HAR,再用 Python 解析 HAR 文件。
- HAR 导出最稳:启动
mitmweb→ 操作 App → 点击右上角Export → Export HAR file→ 用haralyzer库解析:HarParser.from_file("xxx.har").pages[0].entries - 如果坚持用 mitmdump 实时导出,建议按 domain 分文件,用
time.strftime("%Y%m%d_%H%M%S")命名,避免覆盖 - 注意字段清洗:
flow.request.query是 parsed dict,但flow.request.urlencoded_form才是 POST 表单内容;flow.response.json()是快捷方法,内部已处理编码和 gzip
真正卡住的从来不是 mitmproxy 本身,而是证书锁定、代理感知、动态密钥这三层防御。能跑通 demo 不代表能跑通目标 App,每个 App 的反调试策略都得单独应对。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











