前些天看到这篇帖子,其中提到的保护网站安全的措施中着重提到了 IP 地址应该避免泄露.考虑到近期以来本站常常遭到(疑似的)攻击,是时候好好地研究一下这个问题了.
只是一开始我不太情愿而已啦~Cloudflare CDN 在国内明明就是云减速,用上之后访问速度真的变慢了
先说说思路吧:把整个网站都放在 Cloudflare 的 CDN 后边,然后禁止除了 Cloudflare 以外的任何人访问服务器(以避免攻击者通过全网扫描 IP 地址的方式找出真实 IP——扫全网没你想的那么难).
这里遇到的第一个问题是,我的服务器上除了这个网站,还跑着别的杂七杂八的东西,比如一个用 aria2 搭建的离线下载服务,一个 Telegram 反向代理. aria2 的 RPC 接口和 Telegram API 接口都是用的 NOTA.MOE 这个域名下单独的子域名.这些都不是典型的 web 服务(监听着 80/443 端口,给访问者返回一个网页的那种),并不能套上一层 CDN (至少免费版不行.企业套餐可以使用 Spectrum, 见:一,二).而不用 CDN 就不可避免的会造成 IP 泄露,怎么办呢?
考虑再三,我的办法是:重新申请域名,让 aria2 离线下载等服务使用新域名访问, NOTA.MOE 只用于本博客的访问.新注册的域名不使用 CDN, 直接解析到真实 IP, 因此必须要保密.顺便一提,这个新域名要不难记,同时又不能被别人猜到,最好是随机产生的——怎么生成呢?当然是在加密货币中广泛使用的钱包助记词啦~你可以用 MyMonero 这样的在线钱包生成一些钱包,然后挑一段念起来不拗口的助记词当做域名(不要有负罪感,生成钱包只是用一些随机数算出密钥对的过程,生成再多也不会给你的电脑和加密货币网络带来什么开销)当然啦,这样的域名也不是百分百不会被泄露的,常常更换就好了.
上述办法只解决了离线下载这种不用公开的服务的 IP 隐藏问题,而对于 Telegram 反代则行不通——我建一个反代当然是希望大家都能用啊,那域名怎么能保密呢?纠结来纠结去,我最终决定关掉这个反代服务(抱歉!)毕竟这个反代之前用的 TELEGRAMMY.ML 域名已经疑似被墙了 (DNS 污染),可以想象 GFW 对于 Telegram 相关网站的封锁力度是很大的,我换个域名继续提供服务也不能长久.不过授人以鱼不如授人以渔,作为补偿,稍后我会更新 Telegram 反向代理的搭建教程(之前那篇已经过时啦!)同时也推荐大家使用更稳定体验也更好的 Telegram 客户端,网页版毕竟只是以备不时之需的.
然后,对本站启用 CDN. (我顺便开了 DNSSEC) 具体的设置如下,供参考:
Crypto - SSL | Full (strict) |
Crypto - Always Use HTTPS | On |
Crypto - Minimum TLS Version | TLS 1.2 |
Crypto - Opportunistic Encryption | Off |
Crypto - TLS 1.3 | Enabled+0RTT |
Crypto - Automatic HTTPS Rewrites | On |
Crypto - HTTP Strict Transport Security (HSTS) | (在 Caddy 而不是 Cloudflare 中设置) |
Speed - Auto Minify | JavaScript + CSS + HTML |
Speed - Brotli | On |
此外,还需要启用以下 3 个 Page Rules:
目的:阻止 Cloudflare 缓存 WordPress 的管理面板.
目的:阻止 Cloudflare 缓存 WordPress 的文章预览页面.你的网站如果也是 WordPress 的话,这两条规则可以照搬.
目的:实现有 www 跳转无 www. 为实现这一目的,还需要把欲跳转的域名(如 www.nota.moe) 解析到任一 IP 地址并开启 CDN, 否则 Page Rules 不会生效.这一点 Cloudflare 做得没有国内几家 DNS 直观,像 CloudXNS 可以直接为域名加一条 301 跳转的"伪解析记录".当然,跳转这件事也可以放在服务器上做,不过我总觉得服务器该干的事越少 IP 就越难泄露...
开头不是说我挺嫌弃这个云减速么...不过看到不费吹灰之力就能启用 TLS 1.3 和 Brotli...嗯,真香
启用 CDN 后像 WP Super Cache 这样的插件就可以删掉了.虽然网上有很多教程教你怎样靠 WP Super Cache + Cloudflare 来让你的网站快得飞起,但是 WP Super Cache 的作者可不这么想.然后可以考虑装上 Cloudflare 的 WordPress 插件.
好啦,下一步,阻止除了 Cloudflare 以外任何人直接访问我的服务器.就这个问题, Cloudflare 已经给出了终极解决方案: Argo Tunnel. 5 美元一个月,不想继续看这篇水文了就乖乖交钱吧(笑~)这个问题花了我相当多的时间,解决途径之曲折可以从我在 Caddy 社区的求助帖中一瞥.
一个自然的思路是,为站点设置 IP 白名单,只允许 Cloudflare 的 IP 访问,这也是开头提到的那篇贴子里建议的方法.然而,在 Caddy 这儿行不通.我不知道为什么(也懒得知道了), Caddy 在处理 IP 白名单时似乎会采用访客的真实 IP——对,不管有没有 Cloudflare 这层代理,它总是能在默认设置下拿到访客的真实 IP——我认为这是一个设计缺陷,是否使用访客真实 IP 应该由用户控制(这也是 realip 插件存在的意义),并且在别的地方,比如日志中,我确实是可以控制 Caddy 使用代理 IP 还是真实 IP 的.这造成的后果是,一旦我设置 IP 白名单,就没人能打开我的网站了,除非他在 Cloudflare 的机房里
2019 年 5 月 26 日更新
关于 IP 白名单的怪异行为,我已经找到了原因,还顺带发现了一个安全隐患.请阅读: Caddy ipfilter 插件的默认设定是不安全的!
因此需要使用神奇的 Authenticated Origin Pulls. 我简单介绍一下这是什么鬼: Authenticated Origin Pulls 是一种双向验证机制.一般的 HTTPS 连接都是单向验证,即只有访客端验证服务器端的身份.而双向验证则是让服务器端也同时验证访客端的身份.通过让 Caddy 要求访客出示一份只有 Cloudflare 才拥有的证书,除了 Cloudflare 以外的任何人都会被拒绝访问.
然而,这还不够,因为双向验证只会在 HTTPS 连接下才会发生,我们需要禁止 Caddy 提供 HTTP 连接.一个自然的思 (cuò) 路 (wù) 是,在配置文件里这样写:
https://example.com { #... }
Caddy 文档指出,在默认情况下(即启用了 Caddy 的 Automatic HTTPS), 就算显式地指定了 https://
Caddy 同样会允许 HTTP 连接,并自动地做一个 HTTP-to-HTTPS 跳转.为了避免 Caddy 这样做,我们需要关掉 Automatic HTTPS, 方法就是提供我们自己的 TLS 证书和私钥. Caddy 社区的 Matthew 大神建议直接使用 Cloudflare 的 Origin Certificates (在 Crypto 标签下可以启用).这玩意其实是 Cloudflare 给你生成的自签名证书,除了 Cloudflare 自己没有客户端会信任这张证书.但这也无所谓,反正在理想情况下你的网站也只应该有 Cloudflare 这一个(真正的)访客.按 Matthew 大神的说法,启用 Authenticated Origin Pulls 和 Origin Certificates 后,你的服务器和 Cloudflare 就建立了一个 "trust/trust" 关系,只有来自 Cloudflare 的请求能被你的服务器信任,也只有 Cloudflare 能信任你的服务器的回应,听起来煞是有趣但请注意, Origin Certificates 对于提升安全性(避免对服务器的直接访问/避免全网扫描)而言意义不大,攻击者可以直接忽略掉证书错误,在没有其他应对措施的情况下照样能访问你的服务器.
综上所述,具体的操作步骤是:
- 在此页面下载 Authenticated Origin Pulls 证书.在控制面板的 Crypto 标签下生成 Origin Certificates 证书及密钥.把这些文件放到服务器上.比如,它们在一个叫
cf-cert
的目录里. - 修改配置文件,加入以下内容:
tls /path/cf-cert/example.com.pem /path/cf-cert/example.com.key { clients /path/cf-cert/origin-pull-ca.crt }
- 在控制面板里启用 Authenticated Origin Pulls. 搞定!
下面,你可以把服务器的真实 IP 写到 hosts
文件里,然后尝试用各种姿势访问你的网站,看看你的浏览器或者 curl
能报出多少种错误来
最后一步!给 VPS 做个镜像,新建实例,恢复镜像,修改解析记录和(可能的)配置文件,然后删掉原来那台机器!现在你的网站就拥有了一个全新的,隐秘性超强的 IP 地址!
当然,这些天研究 IP 隐藏的问题也看到别的一些可能造成泄露的因素,比如站点尝试访问访客提供的网址就存在风险,如果那一个网址是攻击者拥有的,他可以借此得到你的服务器的真实 IP (比如,有的网站会尝试把用户发言内容里的短网址解析成原网址).如果你有隐藏 IP 方面的经验,也欢迎和我分享哦
未完待续.
请继续阅读:我是如何隐藏服务器 IP 地址的?(二)