网站被 Cloudflare 关闭,Turnstile 在每第二个请求中弹出,而布局每两周就会更改。同时,同一服务有一个移动应用程序,它直接访问后端并获取准备好的 JSON——没有挑战,没有标记,字段模式稳定。这就是所谓的“隐藏 API”:未记录但完全可用的接口,官方客户端使用它。
我们逐步分析如何通过 mitmproxy 找到它,如何处理证书固定,以及为什么在没有代理的情况下收集的扩展阶段会崩溃。
为什么要深入应用程序的流量
抓取网页版本和调用私有 API 是成本不同的任务。比较一下:
- 网页。 需要无头浏览器,绕过反机器人,解析 HTML,定期修复选择器。一次请求 = 兆字节流量和几秒的处理时间。
- 私有 API。 普通的 HTTP 请求加上一些头,响应是紧凑的 JSON,带有类型化字段。通常返回的数据比界面显示的更多:内部标识符、标志、服务字段。
移动后端历史上比网页保护得更弱。原因很简单:反机器人平台专门针对浏览器流量(JS 挑战、canvas、行为信号),而移动客户端根本无法通过它们。相反,开发人员依赖于应用程序的静态密钥和 TLS 固定——这两者都在本地设备上解除。
需要什么
- mitmproxy——开源的 HTTPS 代理拦截器(在 GitHub 上超过 44,000 星,当前版本 12.2.2 于 2026 年 4 月发布,要求 Python 3.12+)。可以通过一条命令安装:pip install mitmproxy。支持 HTTP/1、HTTP/2、HTTP/3、WebSocket 和原始 TCP,支持 TLS 1.2 和 1.3。
- 带有 root 的 Android 设备或模拟器。 实践表明,Android 7–11 最为方便:新版本大大加强了对证书的处理。
- ADB 用于与设备连接,以及 Frida(pip install frida-tools)——如果应用程序固定证书,则需要。
mitmproxy 有三个接口在一个引擎之上:mitmproxy(终端 TUI)、mitmweb(网页界面,更适合新手)和 mitmdump(无头,适用于脚本和自动化)。
步骤 1. 启动拦截器
启动网页界面,使其监听外部连接,而不仅仅是 localhost:
mitmweb --web-host 0.0.0.0
默认情况下,代理在 8080 端口启动。首次启动 mitmproxy 时,它会创建自己的证书颁发机构并将密钥放入目录 ~/.mitmproxy。那里会出现四个文件:mitmproxy-ca.pem(证书及其私钥)、mitmproxy-ca-cert.pem(仅证书)、mitmproxy-ca-cert.p12 适用于 Windows 和 mitmproxy-ca-cert.cer——适用于 Android 的格式。
步骤 2. 通过代理引导设备
在手机的 Wi-Fi 设置中选择手动代理:您计算机在本地网络中的 IP 和 8080 端口。接下来,在设备的浏览器中打开特殊域名 mitm.it——这是内置于 mitmproxy 的页面,它会自动识别平台并提供所需格式的证书及说明。
在 iOS 上,过程分为三部分,所有人都忘记了后半部分:通过 Safari 下载配置文件,将其安装在“设置 → 通用 → VPN 和设备管理”中,然后在“设置 → 通用 → 关于本设备 → 信任证书”中单独启用完全信任。没有最后一步,证书已安装但无法工作。
如果不想麻烦 Wi-Fi 设置,mitmproxy 还有 VPN 服务器模式:mitmweb --mode wireguard。设备通过 WireGuard 的标准客户端连接,流量透明地被拦截,无需在系统中手动设置代理。
步骤 3. 主要障碍——信任证书
这里大多数尝试都会失败。问题有两个,且是不同的问题。
自定义 CA 自 2016 年以来不受欢迎
从 Android 7 Nougat(API 24)开始,应用程序默认只信任系统证书存储。如果开发者没有在网络安全配置中明确允许,则会忽略用户 CA——通过信任锚中的 <certificates src="user" /> 块。这是谷歌为了减少攻击面而做出的有意识决定,无法通过手机设置来绕过。顺便说一句,Chrome 也不信任用户证书。在 Android 11 中,限制更加严格。
实际结论:在具有 root 权限的设备上,mitmproxy 的证书需要放入系统存储,而不是用户存储。这就是为什么 root 在要求列表中,而不是“可选”。
证书固定
第二个障碍是固定:应用程序内部携带预期服务器证书的指纹,并拒绝与其他任何人通信。即使是系统 CA 也无济于事。2022 年 ACM 的研究表明,固定在“高风险”垂直领域(银行、出租车、加密货币)中普遍存在,但通常实现不完整,因此可以绕过。
有几种工具可以解决这个任务,它们的解决方式各不相同:
- Frida——在运行时修改行为:拦截证书检查函数并强制其返回成功。应用程序在此过程中不被修改——这是最灵活的选项。典型启动:frida -U -f com.target.app -l ssl_bypass.js --no-pause。
- apk-mitm——自动从 APK 文件中静态去除固定。
- android-unpinner——重新构建 APK,注入 Frida 和解除固定的脚本。
- objection——Frida 的工具包,支持 iOS 和 Android。
- ssl-kill-switch2——在 iOS 和 macOS 应用程序中禁用固定。
如果特定域名被牢牢固定并妨碍工作,可以简单地通过 ignore_hosts 选项将其排除在拦截之外(接受正则表达式)——流量将直接绕过 mitmproxy,而不进行解密。
步骤 4. 找到所需的请求
接下来是例行工作。打开应用程序,执行一个有意义的操作(打开商品卡片、滚动时间线、应用过滤器),查看出现了哪些请求。在终端界面中,这可以快速完成:Z 清除流列表,Enter 打开所选请求,E 导出它——包括准备好的 curl 命令。
在拦截的请求中寻找:
- 端点和参数。 通常它们比应用程序界面使用的要多得多。
- 客户端密钥。 经典的例子——嵌入应用程序中的静态标识符。在著名的 MyAnimeList 公共 API 分析中,这个密钥是头 x-mal-client-id,其值为 6591a087c62b3e94d769cd8e35ffe909,它打开了对 api.myanimelist.net/v3/anime/season 和 /v3/anime 的访问,带有二十多个参数。
- User-Agent。 移动客户端的 User-Agent 是特定的,并作为“通行证”的一部分——在同一个例子中是 MAL (ios, 139)。
- 令牌及其生命周期。 立即查看密钥是静态的还是会更新:这将影响整个收集器的架构。
导出的 curl 方便通过 curlconverter 转换为代码——您将获得一个准备好的请求,使用 requests,然后可以使用普通的 HTTP 客户端,而无需任何浏览器。
步骤 5. 扩展——哪里出问题
在这一点上,所有尝试都感到失望,所有尝试过的人都熟悉这种感觉:从一个家庭 IP 开始,私有 API 在前半小时内响应良好,然后开始返回 429 和 403。移动后端对客户端伪造的保护较弱,但IP 限制更严格——服务器假设一个地址后面只有一部手机,而不是二十个线程的解析器。
因此,实际结论。
- 保持请求的配置合理。 实际应用程序不会每秒发出 50 个请求,也不会严格按照时间表进行。调用顺序也很重要:真实客户端首先请求会话配置,然后请求内容。
- 分散负载到不同地址。 一个 IP = 一部“手机”。有关轮换策略、延迟和指数退避的详细讨论,请参阅 如何通过代理绕过 API 速率限制 的材料。
- 考虑地理位置。 许多移动 API 根据地址国家提供不同的内容和价格——这既是限制,也是机会。
调试方便地在 mitmproxy 内部进行:它可以连接到上游代理。命令 mitmdump --mode upstream:http://example.com:8081 将所有流量转发到上游,授权通过 --upstream-auth 选项以 username:password 格式指定。这样,您可以看到与之前相同的请求,但它们已经从外部地址发出——可以立即检查 API 如何响应特定国家或 IP 类型。
选择什么类型的代理用于移动 API
选择并不是抽象的,而是取决于您假装成谁。
- 移动代理——优先选择。您模拟应用程序的流量,运营商的地址对后端看起来完全自然:由于 CGNAT,实际上有数百个用户共享一个地址,因此这些 IP 的限制更宽松。适合 4G/LTE 移动代理。
- 住宅代理——如果数据量大而与运营商的绑定不关键,则是可行的中间选择:家庭 IP 提供广泛的地理覆盖,价格合理。这是 住宅代理。
- 数据中心代理——仅适用于没有严重地址声誉检查的端点。它们的 ASN 会立即被识别,在移动后端看起来很奇怪:数据中心没有手机。
潜在陷阱,晚些时候才会发现
- HTTP/3。 mitmproxy 支持 QUIC,并默认启用,但在实际移动流量中受到限制:通常需要通过对 ALPN 的操作强制将连接回滚到 HTTP/2。QUIC 在反向和 WireGuard 模式下效果最好。
- 私有 API 会在没有警告的情况下更改。 它没有向后兼容的义务——这是内部接口。User-Agent 中的应用程序版本会在某一天停止服务,收集器会默默开始接收空响应。监控不仅要关注响应代码,还要关注 JSON 的结构。
- 不要混淆“找到了密钥”和“获得了权限”。 静态客户端密钥并不是无限制收集的许可。
关于法律方面
在自己的设备上拦截流量是合法且日常的调试实践,移动开发人员和安全专家都在使用。界限在于:遵守服务条款,不在没有法律依据的情况下收集个人数据(在欧盟,这直接受到 GDPR 的监管),不要触及需要他人授权的端点,并保持负载在不妨碍服务工作的水平。实际的指导原则是:如果数据在应用程序中对任何用户可见,而无需登录账户——您处于相对安全的区域;如果需要他人的账户才能访问——您已经超出了这个范围。
简而言之
这个方案是可行的,节省了与反机器人斗争的数周精力:启动 mitmproxy,将证书放入具有 root 权限的设备的系统存储中,如有必要通过 Frida 解除固定,捕获一个有意义的请求,将其导出为 curl 并转换为 Python。接下来,“绕过保护”的任务变成了“合理分配负载”的任务——通过地址轮换、合理的暂停和正确的代理类型来解决。最简单的开始是使用 移动代理:它们最接近后端期望看到的流量。
