仅靠 Windows 防火墙充当 VPN 网络锁:真的可靠吗?
按接口类型设置的规则可以拦截物理网卡,但第三方隧道常常显示为有线网络。请依次检查分类、端点路由,然后检查 DNS。
问 Windows 防火墙能否单独充当网络锁,你会得到两个自信却互不相容的答案。一种说法是按接口类型的规则就能包办一切;另一种说没有脚本根本不行。两者描述的其实是同一机制的一半。防火墙能够表达阻断,而结果是否真正故障关闭取决于三件事:Windows 如何归类隧道网卡、端点例外是否仍然有效,以及名称解析与 IPv6 是否被覆盖。任何一项出错,机器要么泄漏,要么彻底断网。
三个条件,顺序如下
第一个条件是分类,它决定你想要的规则是否表达得出来。Windows 防火墙规则可按接口类型限定:有线、无线或远程访问。若策略要在物理类型上拦截出站流量、同时放行隧道,只有当 Windows 把该隧道识别为远程访问时才成立。
第二个条件是端点例外。在任何隧道建立之前,客户端必须通过物理网卡访问 VPN 服务器,因此对那块网卡的全面拦截,恰好会挡住那个让拦截变得多余的连接。例外必须指明服务器及其端口,数据包必须从物理网关出去,而不是进入一条尚未建立的隧道。
第三个是覆盖面。只拦 IPv4 却忘了 IPv6 的规则集,或者为了端点查询放行本地解析器、从而放行其他所有查询的规则集,恰恰会在网络锁本该覆盖的那个窗口里失败放行。这是设计缺口,而非防火墙缺陷。它也是任何桌面测试都发现不了的缺口。
分类是第一道关卡
在写下第一条规则之前,先看看 Windows 如何看待各网卡。Windows 原生 VPN 连接通常显示为远程访问。自行创建虚拟网卡的第三方客户端常常显示为有线,这意味着限定有线网卡的拦截同时也会拦住隧道。
Get-NetConnectionProfile | Select-Object Name,InterfaceAlias,NetworkCategory
Get-NetAdapter | Select-Object Name,InterfaceDescription,Status,ifIndex
Get-NetFirewallProfile | Select-Object Name,Enabled,DefaultOutboundAction
第三条命令告诉你默认出站阻断是否已经生效,这会改变整个设计的形态。若默认已是阻断,你写的就是放行规则,而不是在宽松基础上的例外,这种姿态更容易推理。
如果隧道网卡报告为有线,单靠防火墙就不是故障关闭设计的合适工具,再怎么调规则也改变不了。这正是每个论坛帖里第二种意见正确的场合。
端点例外需要的不只是规则,还需要路由
假设分类没问题。例外由两部分组成,而它们分属不同的子系统。防火墙规则放行流量,主机路由让它在隧道断开时从正确的接口出去。
New-NetFirewallRule -DisplayName "VPN endpoint allow" -Direction Outbound -Action Allow \
-Protocol TCP -RemoteAddress 203.0.113.9 -RemotePort 443 -InterfaceType Wired,Wireless
New-NetRoute -DestinationPrefix 203.0.113.9/32 -InterfaceIndex 12 -NextHop 192.168.1.1
Get-NetRoute -DestinationPrefix 203.0.113.9/32
没有路由,例外只在默认路由仍指向物理网关时有效。一旦客户端装好自己的默认路由然后挂掉,被放行的数据包就无处可去,连接也无法重建。这种故障看起来像客户端坏了,实际是缺少路由。
例外范围要尽可能窄。一个地址加一个端口可以审查;覆盖服务商整个网段的区间不行。那条更宽的规则还会放行同一服务商托管的其它一切,通常超出你的本意。
DNS 和 IPv6 正是失败放行的地方
名称解析是经典的泄漏点。若端点是主机名,客户端必须在隧道存在之前解析它,这就意味着必须允许物理网卡访问解析器。同一份许可也把其他所有查询放了出去,而一次查询就足以暴露你即将访问什么。
IPv6 是第二处。为 IPv4 写的规则覆盖不了另一个协议族,而许多客户端只安装 IPv4 路由。因此具备原生 IPv6 连接的机器可以在 IPv4 侧被牢牢阻断时继续与互联网通信,而网络锁始终报告成功。
| Gap | What leaks | Control |
|---|---|---|
| Resolver permitted for endpoint lookup | Every name queried while down | Pin the endpoint as an address, or block non-tunnel DNS |
| Rules only for IPv4 | Full IPv6 connectivity | Add the same rules for the other family |
| Application bound to physical interface | Its own traffic | Firewall cannot fix this; change the binding |
第三行值得理解而非绕开。防火墙决定的是数据包,而不是应用请求使用哪块网卡;显式绑定网卡的程序往往难以约束。这正是支持在应用之下工作的客户端侧网络锁的理由,而不是增加规则的借口。
测试要停掉客户端,而不是拔掉网线
唯一有意义的测试,是模仿你所防范的那种故障。停掉服务、杀掉进程,或者禁用客户端创建的网卡,然后尝试访问互联网和一个域名:
Stop-Service -Name "YourVpnService" -Force
Test-NetConnection -ComputerName 1.1.1.1 -Port 443
Resolve-DnsName example.com
Test-NetConnection -ComputerName 2606:4700:4700::1111 -Port 443
三者都应当失败。若第一项成功,说明阻断未生效;若第一项失败而第二项成功,说明存在 DNS 泄漏;若第三项成功,说明 IPv6 未被覆盖。每种结果都恰好指向上面的一处缺口。
睡眠和唤醒之后要重测,因为当 Windows 判定网络为公用或专用时,防火墙配置文件会切换,限定于某个配置文件的规则也随之改变。只在桌面上成立、一上火车就失效的设计,是只测过一次的设计。
如果分类关卡或 DNS 要求让单靠防火墙的方案行不通,客户端侧网络锁才是诚实的答案。如果隧道终止在路由器上,策略就该由路由器掌管,因为那里的一条规则覆盖其后的所有设备,也不取决于 Windows 如何命名网卡。