再谈家庭宽带架设 HTTPS 防嗅探。
先说目标:
我的目标是在公网任意位置(公司、移动网络、手机 APP 等)通过 HTTPS 协议可以访问到位于家中 NAS 上提供的 HTTPS 协议服务,譬如 Seafile (实际上 Seafile PC 客户端和手机客户端在 auth 认证阶段也是走 HTTPS 协议的),但是又不会被探测到,或者说即便探测到了,也无法在第三方进行复现,从而避开监管不给 G0v 添麻烦。
目前的已有方案:
由于 `HTTPS` 协议中客户端发送的 `SNI` 会泄漏 `server_name`,可能会被 ISP 嗅探到,然后 `ESNI `也迟迟没有实装,再者即便实装了,大量客户端(譬如手机 App 、浏览器等)在没有得到 `DoH` 等安全 `DNS` 支持的情况下,大概率还是会直接发送 `server_name` 从而导致域名被泄漏,所以等 tls v1.3 esni 不现实。 然后我在测试机上部署且体验了 SNIProxy,也不是绝对满足需求,毕竟这玩意儿只能防止直连端口证书泄漏域名,但是正常访问握手时 client hello 发送 server_name 的问题还是没有解决。 至于 Frp 、SSH 、VPN 隧道等方案也不完美,不具备 **从任意设备,任意公网访问** 这个先决条件。
我的想法:
想了一个折中办法,实现上比较麻烦,也有一些小瑕疵,先抛砖引玉聊一聊?也或者如果有现成的类似的玩意儿也可以直接发给我玩玩? 首先,我们需要一个中间服务器,负责在上面跑一些自己写的脚本,但是这个服务器只作为一个类似前期握手的存在,并不参与具体的流量转发。所以一般来说服务器用最便宜的 VPS 即可,要求具有 IPv4 公网 IP 和低延迟+稳定,对硬件性能无要求。 然后,家里的 NAS 也需要进行一些调整,同样跑一个脚本执行一些额外操作。 最后,具体的实现是这样:
- 正常解析域名 seafile.yourdomain.com 的 A 记录到 VPS 上,客户端正常请求 https://seafile.yourdomain.com
- VPS 上的脚本监听且收到请求后,先挂起请求,然后通过任意加密方式(比如加密的 SSH 隧道)连接家中的 NAS,并且将本次请求中的客户端公网 IP 发送到 NAS 的脚本上
- NAS 的脚本接收到这个公网 IP 后通过 iptables 操作防火墙允许这个 IP 从公网访问 NAS 的 https 服务,并且标记这个 ip,设定一个定时器在 N 秒后移除这条白名单规则,这个参数 N 可配置,一般默认 30-60 秒这样。
- NAS 通知 VPS 已设置好白名单,以及过期时间 N,VPS 上标记该域名白名单状态和过期时间。这样在过期时间内该域名的后续请求不再挂起而是直接放行,参见下一步操作。
- VPS 不再挂起 https 请求,返回 302 状态,重定向该请求到另外一个域名 seafile.fakedomain.com 。这个新的域名是直接解析到家庭宽带的公网 IP 的。
- 客户端收到 302 状态后跟随跳转重新请求到 seafile.fakedomain.com (即 NAS )上,由于白名单的存在,通讯正常处理。
- 安全起见,NAS 上仍然部署 sniproxy,丢弃非 seafile.fakedomain.com 的访问,防止直接端口探测。
这样一套组合拳打下来,优缺点分别如下:
优点:
- seafile 等自建云盘的文件传输是直接 客户端<–>NAS,无需第三方中转,家庭宽带的带宽上限下限可以发挥到极限。
- 即便 ISP 采用 TCP 包拦截抓到 client hello 中的 server_name(seafile.fakedomain.com) 也无法直接访问,因为第三方请求 IP 不在 NAS 的白名单中
- 理论上客户端无需进行特殊配置即可支持。(浏览器默认支持 301 302 跟随跳转,其他客户端就看代码本身了)
缺点:
- 仍然需要一台中间服务器,当然了,最最便宜的 10 刀一年的垃圾 vps 就行了。
- 需要客户端支持 http 301 302 跟随跳转,如果客户端的 http request 是自己写的,只接受 http code 200,其他默认 return error 的话,我这个方案就嗝儿屁。当然了,正常的网页浏览器都是支持的,怕就怕第三方手机 app 这种。譬如 seafile 的手机端认证时是采用 https 的,是否会跟随跳转我暂时没有测试。
- 如果 nas 是跑云盘的话,大流量大带宽的使用仍然会被运营商发现,这个真的没有办法……
总结:
所以,如果你只是要访问家中的网页 https 服务,流量不那么大的那种,又不想被运营商扫到你的端口进行各种探测抓包的话,我这个方案似乎可行?