所有文章 → 文章详情

EC2 + Cloudflare 避坑指南:封杀非 Cloudflare 流量

恶意爬虫?和我的 Cloudflare 规则说去吧!

这其实不是什么复杂的事情,但是容易被经验不足的初学者忽略,在此献上我的中招记录。

长话短说:

重要

只开 Cloudflare 小黄云代理并不代表源站就安全了,甚至可以说源服务器依然处于裸奔状态。必须要辅以回源 IP 限制或是 mTLS 认证才能以避免未经授权的访问绕过 cf1 直击源服务器。

当然,如果你想了解这是为什么,或者想了解如何配置 EC2 实例的出入站策略,欢迎继续看下去。

1. cf 即 Cloudflare 的缩写,本文将会延续使用此缩写,并不再说明

一切的开端。。

笔者最近在打黑客松,提交需要部署 API 后端到公网上做演示用,然而我在英国并没有服务器,所以临时入坑了亚马逊云的 EC2,在上面部署了我的 API 后端。

因为没有钱,租的免费的实例性能实在弱鸡,我在前面套了一个 Cloudflare 代理,并设了一系列规则和速率限制防止被搞炸。Cloudflare TLS 设置为严格,且服务器只接受 443 端口上的 HTTPS。

这么操作看似没有问题,而且我从第一次设置 DNS 记录时就开启了 cf 的小黄云代理,我完全没有在 DNS 记录历史中泄露过源站 IP,理论上我的源站应该是安全的,对吗?

两天后,有人问我的项目网站怎么一直报错,我登上服务器一看发现崩了,再看 nginx 日志发现有许多显然通不过 cf 规则的请求,来源 IP 也不属于 cf,我才发现原来我的服务器能被跳过 cf 代理直接访问。

原因

在理想情况下,cf 的代理模式确实为源站提供了一层隐身衣:由于 DNS 解析记录全部指向 cf 的 IP,源站 IP 理论上与公网是物理隔离的。然而,事实证明,源站 IP 泄露的途径多到几乎难以防住,任何一个环节的疏忽都可能导致源站 IP 暴露。

你可以试试在 censys 等平台上查询你自己的主机名,也许会惊讶地发现自己的源 IP 早已暴露。

至于源服务器的仅 HTTPS,看似可以拦截直接对 IP 的访问,让我们举个例子:

假设你的源站 IP 是233.252.0.123,且源服务器开启了强制 HTTPS,此时正常的浏览器访问233.252.0.123或是curl 233.252.0.123是不会成功的。这造成了“源服务器是安全的”的假象。

这是因为服务器证书是对域名而不是对 IP 生效的,所以客户端这里证书校验失败就停止了;然而这里的证书校验就像 HSTS 一样,是一个君子协议,只在客户端发生,你只需要用curl -k就可以忽略它,攻击者也一样。

如果你的源服务器恰好没有严格 SNI 或 Host 验证,那么此时就可以绕过 cf 连上了,你可以用如下命令来测试:

curl -k <origin_ip>

<origin_ip>替换为源服务器 IP

当然,使用前文说到的查询工具,或者其他方式,攻击者也可以较为轻松的获取到服务对应的主机名,此时加上源站 IP,即使是严格 SNI 或者 Host 验证也不好使了。

假设你的源站 IP 依然是233.252.0.123,并解析到了example.com这个主机名上,那么攻击者就可以轻松的让请求携带正确的主机名上下文,绕过 cf 进行连接,你可以用如下命令来测试:

curl -k <your_domain> --resolve <your_domain>:443:<origin_ip>

<origin_ip>替换为源服务器 IP,并将<your_domain>替换为指向服务所在的主机名

此时因为服务端不对客户端做任何身份限制,只要主机名对上号了就允许访问,于是照样可以绕过 cf 直达源服务器。

解决方案

读到这里你应该已经理解问题所在了,cf 代理相当于只是给服务器加了个门卫,但并没有把后门关掉,我们需要让服务器只听门卫的话。

。。。

补充说明

解决方案正如我上文所说,要对客户端身份进行限制/认证,要么限制回源 IP,要么用 mTLS,今天写不动了,之后找个机会写完