ProxyPin Flutter 应用证书固定绕过原理
Flutter 抓包为什么特别难
普通 App vs Flutter App 的证书处理
| 类型 | 证书信任来源 | ProxyPin 能否抓 |
|---|---|---|
| 原生 Android App | 系统证书池 | Android 7.0+ 默认只信任系统证书,用户证书不信任 |
| 原生 iOS App | 系统证书池 | 信任系统中手动安装的证书 |
| Flutter App | Dart HttpClient 自带验证 | 默认不接受 ProxyPin 的根证书 |
Flutter 的 HTTP 层不走操作系统的证书验证,而是 Dart 的 HttpClient 自己做证书校验——它只信任通过 SecurityContext 显式配置的受信任根证书。
证书固定(Certificate Pinning)
更严格的情况——App 除了常规的证书链验证,还会比对服务器证书的指纹(SHA-256),只接受预定义的那几个证书。这被称为"证书锁定"或"SSL Pinning"。
Flutter 的 dio 包还提供了专门的拦截器实现 Pinning:
// Dio 证书固定示例
Dio().interceptors.add(PiniaInterceptor(
certs: [pinningCertBytes],
));
ProxyPin 的解决方案
ProxyPin 内置了 Flutter 证书固定绕过逻辑,核心思路是:
- 识别 Flutter 流量特征:Flutter 的 HTTPS 握手有独特的 JA3 指纹
- Dart 层 Hook:在 TLS 握手环节拦截证书验证逻辑
- 替换证书链:将服务器证书替换为 ProxyPin 自签发的受信任版本
无需修改 App 源码
这是 ProxyPin 最大的优势——不需要:
- 给 App 加 Frida 脚本
- 修改 App 的
network_security_config.xml - 给 Dart 代码加
badCertificateCallback空实现 - 重新编译 APK
直接扫码连接就能看到 Flutter App 的 HTTPS 流量。
与其他工具的对比
| 工具 | Flutter 抓包支持 | 是否改 App |
|---|---|---|
| ProxyPin | ✅ 原生支持 | ❌ 不改 |
| Charles | ⚠️ 手动配置 | ⚠️ Android 需加 network_security_config |
| mitmproxy | ⚠️ 复杂 | ❌ 不改,但需手动导入证书 |
| Frida + Objection | ✅ Hook 绕过 | ❌ 不改,但需要 Frida Server |
| SSLUnpinning | ✅ Xposed 模块 | ❌ 不改,但需要 Xposed/Root |
验证 Flutter 抓包成功
- ProxyPin 桌面端启动并 HTTPS 证书已安装
- 手机扫码连接电脑
- 打开目标 Flutter App
- ProxyPin 请求列表中应该能看到 Flutter App 的流量
- 点击请求查看响应体——能看到明文 JSON 内容就算成功
如果还是抓不到
可能的原因和排查步骤:
- 证书没信任:回到 HTTPS 证书配置 检查
- Flutter 版本太老:极老版本的 Flutter(<1.17)可能不走 Dart HttpClient 的标准路径
- App 用了自定义 HTTP 库:极少数 App 直接用
dart:io的 Socket 自建 HTTP,绕过所有标准客户端。这种情况 ProxyPin 也无能为力 - TLS 1.3 兼容性:极个别场景下 TLS 1.3 握手异常,在 ProxyPin 设置中临时关闭 HTTP/2 和 TLS 1.3 试试
为什么只有 ProxyPin 有这个能力
Flutter 的跨平台编译特性让它的 HTTPS 栈完全独立于系统层,传统工具(Charles、mitmproxy)都只在系统层做 MITM,碰不到 Flutter Dart 层的证书验证。ProxyPin 的开发者恰好是 Flutter 社区活跃贡献者,针对性地在 Dart 层做了绕过处理——这是其独特优势。