你开启了无线调试,连上一台笔记本电脑,在 VPN 开着的情况下会话仍然可用。这看起来像是有什么东西绕过了隧道。几乎可以肯定并不是。调试会话和应用访问网站的请求是两种不同的网络关系,只有其中一种才应该穿过隧道。

我两次遇到这种误读:一次是手机和笔记本连在同一个 Wi-Fi 上,另一次是重启之后配对依然保留。两次 VPN 都在按配置正常工作。

先给观察命名,再给缺陷命名

在提出泄漏结论之前,可能先发生了三种事件,它们不能互相替代。工具可能发现了一个服务,设备可能批准了一台工作站,或者一个已授权的会话确实在传输命令和字节。写清楚你看到的是哪一种,因为每一种能证明的东西都比人们以为的少。

发现通常是 mDNS 或端口扫描。配对是在手机上做出的注册决定,用用户输入的配对码确认。会话存活意味着流量在两个已配对的端点之间移动。这些都不能说明应用的 HTTPS 请求去了哪里。

把目的地、接口、地址族、时间戳和用户配置一并记录在这次事件上。缺少这些细节,就无法把观察结果与预期的本地网络策略或当时运行的 VPN 版本作比较。

为什么两条路径永远不会相交

无线调试是进入设备的入站连接。adbd 在绑定到 Wi-Fi 接口的端口上监听,工作站在配对之后才连上它。方向很重要:你的笔记本伸进手机,而不是反过来。这与出口泄漏正好相反。

应用的互联网流量经由 VpnService 安装的隧道接口出去,并按 UID 和路由规则匹配。adbd 是以 shell 用户运行的系统守护进程,不属于那套路由集合。即使每个应用都被固定到隧道上,它仍留在底层 Wi-Fi 链路上。

锁定模式对受覆盖的应用强制执行隧道。但它不会把监听套接字变成出口路径。

所以可用的 ADB 会话和可用的断路开关可以毫无矛盾地共存。要证明泄漏,你必须观察本应被阻止的那个方向。

出口测试实际上是什么样

测试受覆盖的应用,而不是调试通道。刻意制造失败条件,然后发出一次全新请求并记录结果。

  1. 确认 VPN 是唯一路径:开启始终开启的 VPN,并选择在没有 VPN 时阻止连接。
  2. 用受支持的方式停止 VPN,确认应用报告没有网络连接。
  3. 从该应用发出一次无害请求,记下它是失败还是成功。
  4. 分别在无线调试开启和关闭时重复,以隔离变量。

在这些条件下被阻止的请求才是证据。成功的 ADB 会话不是,终端应用的一次 ping 也不是。

如果锁定开启时请求确实成功,记录应用的 UID 及其 VPN 许可、当前网络和客户端版本。这个组合才是真正的发现。

配对比会话活得更久

配对是持久状态,不是做完线缆测试就能忘掉的握手。Android 的调试文档描述了无线流程,并指出这种关系会一直保留,直到被明确忘记或授权被撤销。

在归咎于隧道之前,先检查还有哪些授权仍在。打开无线调试,查看已配对的设备,把不再认识的条目全部忘记。在工作站上运行 adb devices 看哪些条目仍有响应,用 adb disconnect 断开过期的条目。关闭无线调试会彻底关闭监听端口。

在共享或不受信任的网络上,请保持关闭。在你无法控制的网络上保留持久授权,比假设的 TUN 绕过是更大的问题。

在提交那个缺陷之前

有用的报告会点名失败的确切边界。写明设备型号和 Android 版本、VPN 客户端及版本、是否启用了锁定、应用包名和 UID,以及手机所在的网络。再加上产生这次观察的命令或请求,以及发生的时间。没有这些,没人能复现你声称已经损坏的边界。

不要为了让测试看起来更戏剧化而关闭强制执行,或在不受信任的网络上暴露调试。那会改变你正在测量的系统,并留下无人能复现的证据。

如果你唯一的证据是 VPN 开着时 ADB 连上了,那你量错了路径。先重新做应用层测试;答案通常就在那里。

相关文章