前景提要:通过 UA 判断对搜索引擎爬虫不限流的方式非常容易伪造,一般写爬虫的人或者攻击者都是直接用的搜索引擎爬虫的 UA。
根据谷歌官方的建议,最好的方法是通过反向 DNS 解析来判断搜索引擎爬虫。
在 Github 上找到了这个 nginx 模块:nginx-http-rdns

感觉 UA 检测像是自己骗自己
——高一某 dalao

反向 DNS 解析的若干好处

Nginx 安装 rDNS 模块

(不完全参考 nginx-http-rdns wiki

因为 Nginx 是用 C 写的,安装 Nginx 模块是要重新编译 Nginx 主程序的……

先在 Github 上克隆这个项目,注意不能直接放到 Nginx 的安装目录里,不然安装模块的时候会报错。
./configure 的时候添加参数:--add-module=/path/to/nginx-http-rdns,然后重新 make & make install 即可。
不过我用的是 lnmp1.6,所以只需要在 lnmp.conf 里增加这个参数,然后 upgrade.sh nginx 即可。

配置

这个模块的文档对用法写得很详细了。
首先要设置一个类似 DNS 服务器的东西,既然服务器在阿里云,就用阿里云的 DNS 好了(如果服务器在国外还是推荐 1.1.1.1 或者 8.8.8.8 吧):

resolver 223.5.5.5;

我们的需求是:先判断是否搜索引擎 UA,如果是则 rdns on 进行反向 DNS 查询,如果查询到是 *.googlebot.com 或者 *.baidu.com 或者 *.baidu.jp 就不限流,否则限流。

配置文件如下(带了 WordPress 的伪静态配置):

location /
{
    resolver 223.5.5.5;
    if ($http_user_agent ~ .*(Googlebot|Baiduspider).*)
    {
        rdns on;
    }
    error_page 418 = @human;
    recursive_error_pages on;
    if ($rdns_hostname !~ .*(baidu.com|baidu.jp|googlebot.com|google.com))
    {
        return 418;
    }
    try_files $uri $uri/ /index.php?$args;
}
location @human
{
    limit_req zone=reqlim burst=5 nodelay;
    #limit_conn perip 5;
    #limit_rate 500k;
    try_files $uri $uri/ /index.php?$args;
}

效果测试

仍然用 Apache 的 ab 工具测试,假装我们是谷歌的爬虫:

ab -n 30 -c 1 -H "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://skywt.cn/

返回结果:

Complete requests:      30
Failed requests:        12
   (Connect: 0, Receive: 0, Length: 12, Exceptions: 0)
Non-2xx responses:      12

拒绝了 12 次请求。

更新:由于本站转移到 Typecho,换了个简洁的主题(甚至不加载花里胡哨的 jQuery),网站速度大幅加快,现在直接在任何一个博客页面一直按刷新就可以刷出 503 错误 =_=


关于这么做的弊端,资源消耗个人觉得没什么,毕竟要判断是搜索引擎的 UA 才会去查询,正常用户访问基本无影响。而且访问网站本来就是要 DNS 查询的。

但是!!反向 DNS 的伪造比我想象的要容易得多!

rDNS 的伪造

国内服务器一般都没有设置 PTR 的入口,像国外 BandwagonHost 就提供了设置 PTR 记录(就是反向 DNS 记录)的入口:

BWH set PTR

This page allows you to change the PTR record (Reverse DNS record) for an IP address.
PTR records are primarily needed for mail to work properly. If you do not know what value to use for a PTR record, then use your server hostname.

连正向 DNS 验证之类的操作都不需要???

我尝试把我另一台 bwh 上的服务器 PTR 设置成 googlebot.com,然后就成功了……成功了……

通过 host 命令查询 IP,得到结果:

$ host 65.***.***.***
***.***.***.65.in-addr.arpa domain name pointer googlebot.com.

在那台服务器上对网站压力测试,得到结果是

Complete requests:      30
Failed requests:        0

果然没有拒绝请求……(吐血)

再次正向验证

谷歌的建议里还有一步,就是再查询反向 DNS 得到的域名,检查解析出的 IP 是否与 IP 符合。这样正向也需要解析,如果没有域名的所有权是做不到的。

但是,百度并没有提供正向解析的保证!
对百度示例的爬虫 IP 123.125.66.120 反查得到 baiduspider-123-125-66-120.crawl.baidu.com,再次正向查询:

Host baiduspider-123-125-66-120.crawl.baidu.com not found: 3(NXDOMAIN)

根本没有……所以百度的蜘蛛没法这么判断……

后记

果然维护 IPlist 是最靠谱的方式吗……

内心 OS:管你呢,谁 tm 用辣鸡百度。