每当有人问 VPN 是否隐藏了自己的流量,三个观察者就被折叠进同一个问题:他所接入的网络、他手中的机器,以及隧道的运营者。三者学到的东西不同,隧道也以不同方式改变这三种视角。倒过来想、从被提出的主张出发会更有用,因为经不起检验的正是主张本身。先决定你需要哪一种主张,再用它来衡量工具。

主张一:没有人能读到流量

从最窄的主张开始:载荷保持不可读。路径上的被动观察者看不进 TLS 会话,所以对已经在用 HTTPS 的站点,隧道几乎不增加什么,对两端更是毫无作用。打破这一主张的是控制设备的一方,因为检查代理会终止连接,并用机器已经信任的根证书重新签名。这就是为什么证书链上写着安装该根证书的机构名称时,锁形图标依然出现。

security find-certificate -a -p /Library/Keychains/System.keychain | openssl crl2pkcs7 -nocrl -certfile /dev/stdin | openssl pkcs7 -noout -print_certs | grep subject
certutil -store Root

在 macOS 上,那条命令会为机器钥匙串中的每个证书打印一行主题,而不打开任何窗口;在 Windows 上,certutil -store Root 列出的正是 certlm.msc 以图形方式显示的同一个存储。属于学校、雇主或某款网络安全产品的根证书,才是要找的条目。找到一个只能证明拦截是可能的,不能证明它正在发生。

你在这方面能做什么是政策问题,而不是技术问题。从并不属于你的硬件上移除描述文件或检查根证书,通常违反可接受使用协议,而管理系统往往会察觉并重新下发,所以「设备所有者不得读取你的流量」这一要求,需要的是另一台设备,而不是另一项设置。

主张二:没有人能看到你去哪里

目的地是更难的主张,因为页面加载之前就有两次暴露。查询会发给系统配置使用的解析器,而答案对承载它的网络可见。随后 TLS 握手会把请求的服务器名以明文送出,除非两端都支持 Encrypted Client Hello。两次暴露都不涉及解密,所以隧道对两者都不起作用。

resolvectl status | grep -A2 "Link"
nslookup example.com

真正在用哪个解析器决定了暴露程度,而这件事可以测量,不必争论。在 Linux 上,resolvectl status 会按链路打印 DNS 服务器,输出会告诉你应答的是站点解析器还是被推送的那个。Windows 用 nslookup example.com 回答同一个问题,它输出的第一段就是作出应答的 DNS 服务器。

当笔记本在隧道建立之前就向站点解析器发问,或者配置文件到达时没有替换服务器、旧的仍在使用,管理员仍然能在不解密任何内容的情况下收集主机名。浏览器里的加密 DNS 要么绕过被推送的解析器,要么被彻底阻断并以关闭状态失败。出口运营商从自己一侧看到同样的名字。因此更换解析器并不能把这次暴露从隧道运营商那里移开。

主张三:没有人知道你连过网

第三项主张是隧道无法支撑的,因为 数据包仍然要穿过本地网络。那个网络会知道端点地址、大致流量、时间,以及存在一个长期加密会话,这些足以阻断、限速或者仅仅是注意到。读不了数据包的防火墙仍然可以拒绝放行。被观察并不等于无人观察:你只是挪动了观察者,并没有删掉它。

拆分隧道,以及 任何忽略推送路由的应用程序,都会在隧道之外产生与从前看起来完全一样的流。细心的观察者最先注意到的正是这些流,而客户端路由表会显示哪些目的地被排除在外。

另一端的运营商掌握着这幅图景的镜像:出口地址、时间、流量,通常还有站点名称。你的提供商成了拥有观察点的一方,这与隐身是另一笔交易。选择你信任的提供商是真正的决定;把结果说成无人观察则不是。

决定你需要哪一项主张

在动客户端之前,把需求写在一行里:隐藏内容、隐藏目的地,还是隐藏你是否连过网。内容已经由 HTTPS 加隧道处理,而目的地需要完全绕开站点设备的解析器与路径。

第三项需求最棘手,因为某处仍有东西明显地连着,无论是否加密。没有任何客户端设置能改变这一点。如果需求与政策彼此分离,那道缺口属于与政策所有者的对话,而不属于客户端选项。能回答这个问题的人,正是写下政策的人。

相关文章