再谈家庭宽带架设 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-13 12:08:22 +08:00
@myqoo 打哑谜可就没意思咯。
binkcn
2020-05-13 12:09:52 +08:00
@noahzh 超大流量的问题,我在主题的“缺点”第 3 条中已经提到了,我自己的应用场景没有那么大的持续流量。:)
myqoo
2020-05-13 14:16:10 +08:00
@binkcn 最简单的办法,就是套一个 100% 尺寸的 iframe,所以就不用重定向了~~

而且 iframe 可以任意端口,不用 443 。并且可以用不固定的泛域名,用泛域名作 token (里面绑定 IP,或者一次性的 id 等),这样就用不着 iptables 了~


当然更高的办法就是用 Service Worker,这样 iframe 都不用了。
myqoo
2020-05-13 14:22:05 +08:00
当初用这个办法,给没有公网 ip (但可以 tcp hole )的家宽搭了个网站~
binkcn
2020-05-13 16:38:59 +08:00
@myqoo 来自手机客户端的 API 接口请求怎么用 iframe ?注意审题……

:)
myqoo
2020-05-13 16:46:50 +08:00
@binkcn 非浏览器 UA 那还是走 30X 吧~
binkcn
2020-05-13 17:46:20 +08:00
@myqoo

其实 30x 方案也不是完美的,主要一点就是 http 协议的 redirect 如果重定向出现跨域,那么 header 中的 Authorization/WWW-Authenticate/Cookie 是不会跟随重定向的。

所以今儿早上我手机客户端 Seafile 测试的时候,https api 拉取一直失败,随后 debug 发现 seafile 的 web api 要求在 header 中使用 Authorization 发送 token 做身份验证。

当然,机智如我,在 proxy-knocker 中增加了检查,如果有上述 header,那么将其转换为 GET 参数拼接到 请求的 uri 中,然后在真实服务器( nas )那边套了一层 nginx,判断如果 GET 中有这些特殊参数,那么将其转换为 header,并且用 proxy_set_header 专递给 proxy_pass 后端服务器。

最后问题解决了,手机客户端正常使用中。

回头再优化一些其他问题吧,譬如 ssh 连 nas 开 iptables,我觉得不安全;还有每次请求仍然会走一次 vps 做 redirect,性能上感觉有点不完美。
whitegerry
2020-05-13 17:51:14 +08:00
@binkcn ssh 这个绕一下应该可行吧,比如 nas 上给 ssh 开个普通帐号,vps 连 ssh 在该用户下写个文件,内容就是 ip 之类,然后 incron 监视这个目录修改,由 root 去修改 iptables 。
nereus
2020-05-13 23:09:07 +08:00
1.要用宽带的公网 ip 就不可能实现,https 流量与 tls 加密的其它流量没有区别,但是运营商可以用 ip 反响查域名,任何端口都没用。
2.可行的办法是经第三方 ip 中转,只要用了 tls 流量就无法区分,逐个试探全部端口不现实,反向 dns 查询也查不到
noahzh
2020-05-14 08:22:37 +08:00
@binkcn 超大流量是运营商定义的,你只要是一直是固定端口传输,后台就会记录的.没有什么成本事情.
binkcn
2020-05-14 09:18:29 +08:00
@whitegerry

这个办法也不是没有想过,但是既然始终都要在 nas 上额外做些什么了,不如直接再写个服务丢到 nas 上去,专门用来做这个事情,然后服务本身跑在一个低权限的 local 账户上确保安全。

这里姑且叫它“开门人”服务,这个服务本身收到消息后用私钥解出消息,拿到 ip 和有效时间,开通白名单后自己再管理这个 ip 的白名单过期时间,到期后 iptable -D 移除记录。

这样依赖 proxy-knocker 可以移除对 ssh 的依赖,更轻量化;而且还顺手解决了当前版本没有管理和移除过期白名单记录的问题。
binkcn
2020-05-14 09:20:40 +08:00
@nereus

注意审题,我文中已经说了,目前 esni 方案不可用的情况下,已经不奢望隐藏域名了。所以退而求其次的办法是域名和端口可以让你发现,但是你在第三方设备上直接模拟请求无法复现。
binkcn
2020-05-14 09:22:10 +08:00
@noahzh

你这个倒是提醒了我,nas 上的服务一直采用固定端口的话确实会有风险,后续版本加入动态端口吧,由 vps 上的服务和 nas 上的服务按照预设规则协商就可以了。

:)
myqoo
2020-05-14 10:07:22 +08:00
@binkcn vps 和家宽用同个根域名,配不同的二级域名应该可以吧
andynet
2020-05-14 10:19:38 +08:00
是不是按照你们这种方案,连 VPS 都不用买,跑一个 js 在 cloudflare 的 worker 就好了?
nereus
2020-05-14 12:25:50 +08:00
@binkcn 呵,运营商主要就是靠域名逆解析来查水表,不管你有没有 web 界面,只要能够逆解析就警告。有逆解析之后会扫描你的端口,tcp 逐个链接,连上就算私设 web 不管你是不是 http
binkcn
2020-05-15 09:19:19 +08:00
@nereus

首先,光是靠域名解析就查水表的话,岂不是可以随意栽赃别人?我觉得可能性不大,而且目前没有看到类似被查水表的案例。即便如此退一万步来讲,我这个方案的话,redirect 到 nas 这个步骤可以不用域名解析指向 nas,直接 IP:PORT 即可。 ip 在 nas 上用脚本定时检查更新到 vps 上(类似 ddns 方式),端口用前面说的随机协商方式就行了。

还有,这个方案中,不在防火墙白名单中,第三方 tcp 无法链接。
sadfQED2
2020-06-26 22:02:47 +08:00
巧了,老哥,47 天后和你有了相同的想法

https://www.v2ex.com/t/684494#reply45
DopaminePlz
2020-07-04 10:49:09 +08:00
学习学习
DopaminePlz
2020-07-04 11:13:00 +08:00
非 ITer 。能不能前段网页挂 VPS,NAS 不挂网页,只存储数据?即办公室电脑访问 VPS 只完成认证工作,并为办公室电脑访问 NAS 做好准备,完了办公室电脑直接将照片文档等数据存储到 NAS ?

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

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

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

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

© 2021 V2EX