上篇(传送门)中介绍了Cloudflare Firewall功能,以及编写简单的防火墙规则来保护自己的WordPress站点。但是这些简单的规则还是可以很容易地被攻击者突破,不足以完全保护自己的站点,今天就来说两种小技巧,可以用来编写既高效又很安全的过滤规则。

利用规则优先级

Cloudflare Firewall规则具有优先级,Allow操作的优先级高于Block。而且经过我的测试,Challenge操作的优先级也是高于Block操作的,所以根据这点,可以让符合Allow规则的请求通过防火墙,其余全部拦截。

以保护WordPress的登录页wp-login.php为例,我只允许中国大陆IP访问这个页面,并且要使用新版HTTP协议以及SSL加密来和服务器建立连接,这样的话就可以编写两条规则,一条用来执行Allow(允许)操作,一条用来执行Block(阻止)操作。

允许的规则是这样:

(http.request.uri.path contains "wp-login.php" and ssl and http.request.version in {"HTTP/2" "HTTP/3" "SPDY/3.1"} and ip.geoip.country eq "CN")

这条规则的意思是,当请求路径包含wp-login.php字样,并且使用了SSL加密,以及HTTP版本为HTTP/2、HTTP/3或SPDY/3.1(新版HTTP协议不止HTTP/2一种),还有IP所在地为中国大陆地区。

这条规则对应的最终操作为Allow,所有符合这一规则的请求会被放行,而不符合这一规则的请求会转而进入下一条规则进行判断:

(http.request.uri.path contains "wp-login.php")

这条规则的意思是,当请求路径包含wp-login.php字样。它紧挨着上面一条Allow规则,这是一条Block规则,它负责阻止不符合前一条Allow规则的请求。

执行优先级规则语法执行操作
1(http.request.uri.path contains "wp-login.php" and ssl and http.request.version in {"HTTP/2" "HTTP/3" "SPDY/3.1"} and ip.geoip.country eq "CN")Allow
2(http.request.uri.path contains "wp-login.php")Block
保护 wp-login.php 页面的规则组,符合第一条规则的请求直接放行,不符合的将在第二条规则中被拦截

这样一条允许,一条阻止的规则组,就可以用来过滤不合规的请求,而仅让符合要求的请求通过防火墙。

使用特殊 Cookie 保护站点受限区域

WordPress站点的后台管理区域(wp-admin)是需要着重保护的区域,应该仅允许站点管理员以及站点编辑访问,其余访问需要全部阻止。

由于中国大陆上网用户没有独立IP地址,所以不能在请求IP上下功夫。像国外用户那样仅允许自己的IP地址访问,其余IP地址全部阻止,这在大陆地区是行不通的。

但是仍有一种方法可以确保访问后台管理区域的是站点管理员自己,那就是Cookie。登录进入WordPress的用户会在他们的浏览器上保存来自站点的Cookie用来维持登录状态。正常情况下,当站点服务器收到了这样一组Cookie,就可以认为请求来自已经登录的该名用户。

不过WordPress生成的Cookie是变化的,不是固定的,所以只有WordPress后台才能判断这些Cookie是不是有效,不能让Cloudflare Firewall来判断。那么如何生成既能唯一标识用户本人,又能让Cloudflare Firewall识别的Cookie呢?其实也很简单啦,就是自己规定一个键值对,当成Cookie保存在浏览器中,每次浏览器请求服务器时会自动带上它,当请求到达Cloudflare网络时,会根据防火墙规则来判断这个Cookie是不是存在,不存在的话就阻止该请求。

自己添加一条Cookie记录,在浏览器端就可以实现,打开浏览器控制台,输入创建Cookie的JavaScript代码就可以了:

document.cookie='key=value;secure'

以上JavaScript代码创建了一个键为key,值为value的Cookie,同时规定该Cookie只能通过HTTPS连接发送(secure指令)。

这种方法生成的Cookie为会话级别Cookie,它们的生存时间只截至到浏览器关闭,不会持久化存储,具有更高的安全性。同时Cookie路径为当前所在页面的路径,例如这个Cookie在https://www.foo.com/bar/index.php页面下生成,Cookie路径就为/bar,当访问https://www.foo.com/bar/路径时浏览器会带上这个Cookie,访问其它路径不会带上。如果要访问所有路径都会带上的Cookie,只需要在https://www.foo.com/页面下生成这个Cookie就可以了。

有了自定义的Cookie,接下来就是去Cloudflare Firewall控制台里编写规则来验证这个Cookie,只有携带这个自定义Cookie的请求才会被放行,否则就会被拦截。

执行优先级规则语法执行操作
1(http.request.uri.path contains "/wp-admin" and ssl and http.request.version in {"HTTP/2" "SPDY/3.1" "HTTP/3"} and ip.geoip.country eq "CN" and http.cookie contains "key=value")Allow
2(http.request.uri.path contains "/wp-admin")Block
保护 wp-admin 区域的规则组,符合第一条规则的请求直接放行,不符合的将在第二条规则中被拦截

与保护登录页的规则类似,这里我依然只允许来自中国大陆地区的,并且使用了新版HTTP协议和SSL加密的请求访问。唯一不同的是这里需要对Cookie做校验,判断请求中是否包含(contains)指定Cookie(key=value)。

wp-admin区域比较特殊,对它的请求不仅会来自外部,还会有来自WordPress站点内部的请求,比如WordPress自身的自动更新维护服务,会从内部请求wp-admin区域。这时候,站点服务器在海外地区的小伙伴需要注意,还需要将服务器本身的IP地址也加入Allow规则部分,变成这样:

(http.request.uri.path contains "/wp-admin" and ip.src eq 服务器IP地址 and http.user_agent contains "WordPress/") or (http.request.uri.path contains "/wp-admin" and ssl and http.request.version in {"HTTP/2" "SPDY/3.1" "HTTP/3"} and ip.geoip.country eq "CN" and http.cookie contains "key=value")

这条Allow规则由两部分组成,由OR关系符隔开,前面一部分用来放行来自WordPress服务器内部的请求(来自内部的请求会使用一个类似于WordPress/5.0;https://www.foo.com字样的用户代理字符串,所以我对User Agent也做了判断),后面一部分用来放行来自指定用户的请求。

类似于保护wp-admin区域,对wp-login.php页面的保护也可以加入自定义Cookie校验,这里就不重复写了。

这种自定义的Cookie就像密码一样,为WordPress站点套上了一个保护层,只有持有正确“密码”的请求才能获准通过,否则不予放行。

以上两个小技巧,是我根据Cloudflare Firewall的官方文档总结出来的,在文档里还有更多的规则编写技巧,只不过有些写法不适用于免费的Cloudflare用户,或者不适合中国大陆网络环境的用户,在正式部署之前需要进行测试。

我发现,自从我部署了这套防火墙规则,我的站点再也没有受到过爆破攻击了,Jetpack那个暴力破解攻击拦截次数已经好久没变化过了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注