再谈家庭宽带架设 HTTPS 防嗅探。

2020-05-08 17:13:43 +08:00
 binkcn

先说目标:

      我的目标是在公网任意位置(公司、移动网络、手机 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 也需要进行一些调整,同样跑一个脚本执行一些额外操作。

    最后,具体的实现是这样:
  1. 正常解析域名 seafile.yourdomain.com 的 A 记录到 VPS 上,客户端正常请求 https://seafile.yourdomain.com
  2. VPS 上的脚本监听且收到请求后,先挂起请求,然后通过任意加密方式(比如加密的 SSH 隧道)连接家中的 NAS,并且将本次请求中的客户端公网 IP 发送到 NAS 的脚本上
  3. NAS 的脚本接收到这个公网 IP 后通过 iptables 操作防火墙允许这个 IP 从公网访问 NAS 的 https 服务,并且标记这个 ip,设定一个定时器在 N 秒后移除这条白名单规则,这个参数 N 可配置,一般默认 30-60 秒这样。
  4. NAS 通知 VPS 已设置好白名单,以及过期时间 N,VPS 上标记该域名白名单状态和过期时间。这样在过期时间内该域名的后续请求不再挂起而是直接放行,参见下一步操作。
  5. VPS 不再挂起 https 请求,返回 302 状态,重定向该请求到另外一个域名 seafile.fakedomain.com 。这个新的域名是直接解析到家庭宽带的公网 IP 的。
  6. 客户端收到 302 状态后跟随跳转重新请求到 seafile.fakedomain.com (即 NAS )上,由于白名单的存在,通讯正常处理。
  7. 安全起见,NAS 上仍然部署 sniproxy,丢弃非 seafile.fakedomain.com 的访问,防止直接端口探测。

这样一套组合拳打下来,优缺点分别如下:

优点:

  1. seafile 等自建云盘的文件传输是直接 客户端<-->NAS,无需第三方中转,家庭宽带的带宽上限下限可以发挥到极限。
  2. 即便 ISP 采用 TCP 包拦截抓到 client hello 中的 server_name(seafile.fakedomain.com) 也无法直接访问,因为第三方请求 IP 不在 NAS 的白名单中
  3. 理论上客户端无需进行特殊配置即可支持。(浏览器默认支持 301 302 跟随跳转,其他客户端就看代码本身了)

缺点:

  1. 仍然需要一台中间服务器,当然了,最最便宜的 10 刀一年的垃圾 vps 就行了。
  2. 需要客户端支持 http 301 302 跟随跳转,如果客户端的 http request 是自己写的,只接受 http code 200,其他默认 return error 的话,我这个方案就嗝儿屁。当然了,正常的网页浏览器都是支持的,怕就怕第三方手机 app 这种。譬如 seafile 的手机端认证时是采用 https 的,是否会跟随跳转我暂时没有测试。
  3. 如果 nas 是跑云盘的话,大流量大带宽的使用仍然会被运营商发现,这个真的没有办法……

总结:

所以,如果你只是要访问家中的网页 https 服务,流量不那么大的那种,又不想被运营商扫到你的端口进行各种探测抓包的话,我这个方案似乎可行?

11694 次点击
所在节点    宽带症候群
84 条回复
binkcn
2020-05-11 11:11:52 +08:00
@leafleave
@hymzhek

提到端口敲门的,我统一回复一下吧,经测试,port knocking 有一些局限性:

1 、需要在目标机器开多个端口,如果我程序跑在 nas 上的话,需要在网关路由器做多次端口映射。

2 、经测试,端口敲门逐一连接端口时,如果由于网络波动导致丢包的话,端口敲门失败率非常高。(中间有一个包没收到,顺序就会出错,导致敲门失败)

3 、端口敲门程序,成功敲门后白名单开放的是敲门人的 IP 地址(即我文中的 vps 地址),而我希望是另一个由 vps 指定的 ip 地址,即真正访问者的 IP 地址。

再说一次,我的目的不是单纯为了让我自己访问,而是让其他任意人都能便捷访问。
binkcn
2020-05-11 11:13:02 +08:00
@jiangyang123 是的,又一个看懂我意思的。:)

理论上我这个方法可以让任意访问者无感直连 nas,且第三方即便抓包知道了 nas 的 ip 、port 、domian 。也无法在第三方客户端复现访问。
binkcn
2020-05-11 11:15:26 +08:00
@andynet 如果我没看错的话,你这个方案和 FRP 大同小异,最终流量都是走的 VPS 。

我的方案如果部署完毕的话,VPS 只是相当于初期的一个“可信介绍人”,完成“介绍”(即白名单开启)动作后 VPS 不参与后续的事情。
lifanxi
2020-05-11 12:10:54 +08:00
@binkcn 我也测了一下。群晖那一票 app 似乎都不行,上来就是一堆 POST 请求。
LnTrx
2020-05-11 12:13:23 +08:00
@binkcn
对于端口敲门:
多个端口映射并不复杂,一般路由器的图形管理界面都支持
境内互联的网络波动不算大,通过设定好规则、多次敲门不至于连不上
端口敲门程序可以放在任意托管的静态网页里用 js 实现。用户访问这个页面,白名单开放的就是用户自己。js 检测到开放后,也可以执行跳转

端口敲门的真正问题是没法直接 302,对于非浏览器访问而言不够无缝
LnTrx
2020-05-11 12:16:09 +08:00
顺便一提,楼主的的设想用云函数计算应该就可以实现了,相比买 VPS 可以省不少钱
milkme
2020-05-11 14:49:37 +08:00
有个疑问:现在只要不主动申请,ISP 分配的都是内网 IP,那么在同城 /同 ISP 的情况下,AB 两个用户互联时应该是用的内网 IP,但是通过 VPS 添加的白名单 IP,确是公网 IP 。
binkcn
2020-05-11 15:02:07 +08:00
@lifanxi

你是怎么测试的?

我这里 Seafile 的 /api/auth 认证登录接口也是 POST 的,但是可以跟随 302 跳转。

我是先做了一个地址 A,然后 302 到新的地址 B,用客户端时填写 A 地址,然后发起请求,最后地址 B 上也有 access log 。
binkcn
2020-05-11 15:17:29 +08:00
@talarax7

1 、端口映射这个操作本身没有难度,主要是我不希望开放太多空白端口,哪怕这些端口本身没有任何卵用。

2 、境内波动是小,但是境内的 vps 一来价格贵,二来需要备案才能用域名;所以我这个方案中提到的 vps 一般都指国外那种非常非常廉价的 vps,而境外 vps 的话波动就难说了。 再有一个哪怕 vps 是境内的,但是既然 nas 要提供服务了,如果有多个人在线拉视频流的话,网关上出现丢包也在所难免,毕竟端口敲门这个方案没有什么可用性保障设计,丢包就是丢了。( ps:我测试 port knocking 的时候发现,如果丢包导致顺序出错,重发的时候第一个包会被上一个未完成的队列用来进行 check,然后抛出 error,也就是说短时间内的重试时第一个敲门包会无效化)

3 、js 这个方案也是我正在做的这个东西的最初想法,但是我思考之后决定放弃,一来纯 js 编写的话,端口敲门顺序是暴露的,我正在做的这个东西希望能支持一些简单的认证后再进行敲门和 302 。所以目前是 python 在写,提供一个 web server 监听,允许配置简单的认证( get/post 参数,或 header 头字段,或 basic auth ),认证通过后再通知 nas 开放白名单,并且还会验证是否开放成功,最后才 302 到 nas 上。

总的来说,我目前这个方案各个环节我本地已经跑通,就等慢慢撸代码然后开源发布了。
binkcn
2020-05-11 15:18:54 +08:00
@milkme

首先,我并不考虑你假设的这种情况,然后就是即便同城市,同 ISP,同在一个广域网,2 个 IP 也是无法访问的,有 IP 隔离存在。
baozhuo
2020-05-11 23:12:50 +08:00
感觉理论上应该是可行的,等你开源了我去 star 一波,十一回去我也试试
binkcn
2020-05-12 09:08:59 +08:00
@baozhuo 预计今天会出个第一版吧。会比较粗糙,但是主要功能可用这样。
smileawei
2020-05-12 10:38:29 +08:00
用证书验证的 openVPN 即可。握手的过程类似双向认证。只是所有流量都走在隧道内
binkcn
2020-05-12 16:49:03 +08:00
@baozhuo

小星星拿来吧,哈哈,详见 APPEND 。
whitegerry
2020-05-12 17:59:39 +08:00
如果 nas 只有 ipv6 地址能行不,手机也有 v6 地址?
binkcn
2020-05-12 18:08:02 +08:00
@whitegerry

理论上是可以的,如果只有 ipv6 的话,需要注意的地方有 2 个:

1 、REDIRECT_URL = 'https://nas.yourdomain.com:1443'
重定向目标的域名你要自己解析到 nas 的 ipv6 地址上。

2 、SSH_ADDR = '127.0.0.1'
NAS 的 SSH 地址这里,你填写 nas 的 ipv6 地址试试看? paramiko 的手册上 connect 方法我没有看到明确说是否支持 ipv6,只能你试试看了。


其他就没什么了。
whitegerry
2020-05-12 19:51:01 +08:00
@binkcn
vps 的 v6 没通,nas 没有公网 v4,手机和 nas 都有 v6,vps 可以通过隧道 ssh 到 nas,但是 vps 给到 nas 的是客户端 ipv4 吧,这样的话好像行不通了
myqoo
2020-05-12 20:05:09 +08:00
和我之前想的方案类似。不过我的方案更巧妙,不用 30X 跳转。

熟悉前端的朋友,可以猜猜如何实现~
myqoo
2020-05-12 20:08:43 +08:00
另外,iptables /白名单 最后其实也是用不着的(用我的方案)
noahzh
2020-05-13 08:15:23 +08:00
局端数据一看有大量数据上传,然后端口固定,直接就封你了,哪有你想的那么复杂,你在怎么折腾也是在人家的局域网内,局域网流量监控太成熟了,根本没有折腾必要.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/669709

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX