屏蔽来自网页端的垃圾评论

上一篇提到我把 XML-PRC 的评论功能关掉了,但是效果并不明显,一晚上仍然有超过 20 条垃圾评论。和往常一样,这些垃圾评论被 Akismet 拦截下来,然后被我手动全部清除。

尽管 Akismet 的检测非常有效,几乎没有误伤的情况,但我依然觉得它有点大材小用了。Akismet 的工作原理是把每一条评论都发往 Akismet 的官方服务器,让服务器来判断是不是垃圾评论。它之所以高效是因为,Akismet 监控了大量 WordPress 博客的评论,一旦有某种模式的评论被认为是垃圾评论,所有启用了 Akismet 的博客都可以对那一类的垃圾进行过滤。这样略有一点用牛刀杀鸡的感觉。Akismet 会在网页中嵌入一些代码,虽然不大,但我对网页大小一直都很挑剔,能减则减;并且它会和其它的服务器通信,不仅增加了博客主机的负载,还消耗了更多的流量。

一定有一种更有效、更轻型的方法,可以用来检测并屏蔽这些垃圾评论。

以下是我的方法,它基于两点假设:

  1. 正常读者的浏览器都支持 Javascript。目前主流的浏览器都已支持并默认开启 Javascript,如果你所用的浏览器不支持它,那我也爱莫能助了。
  2. 正常读者都是通过评论框来写评论,而不是通过脚本自动填写的。基本信息如名字、邮箱等可以用脚本填写,这没有问题,但实际的评论内容也用脚本的话,那就说不过去了。另一方面,垃圾评论则有可能是机器自动生成、自动填写的,填写的方式基本是利用 Javascript 直接改评论内容。

基于以上的理论,我在 functions.php 中增加了以下代码:

这是两个全局的常量,用于后续的检测。它们用于生成一个随机数,在服务器端进行后续的检测。

以上代码在评论框中添加一个隐藏的元素“leonax-magic”,它的初始值是 0,当用户填写了评论的内容之后,它的值会变成另一个随机数字,大小介于上述的 $leonax_magic_lower 和 $leonax_magic_upper 之间。这个值有助于我们检测垃圾评论。

以上代码在评论提交之后进行检测,如果“leonax-magic”的值介于 $leonax_magic_lower 和 $leonax_magic_upper 之间,则表示该评论是正常的,反之则说明是垃圾评论。如果是垃圾评论,则只接报错(即在网页中会显示错误信息),而不是像 Akismet 一样存在数据库中。因为根据上面的假设,这样抓获的评论一定是垃圾评论,不需要再审核,于是就直接丢弃。

接下去是一些说明:

1. 为什么要用 $leonax_magic_lower 和 $leonax_magic_upper?
如果垃圾评论的机器蛮得聪明了,学会了在 HTTP 请求中添加 $leonax_magic 的值,我们可以通过改变 $leonax_magic_lower 和 $leonax_magic_upper 的值来继续阻止垃圾评论。

2. 这个机制有多么有效?
目前已使用超过24小时(至 11 月 27 日),没有一条垃圾评论漏网。

全站禁用 XML-RPC 评论

垃圾评论真是头疼,现在每天能收到超过 100 条垃圾评论,并且有上升趋势。

当然垃圾评论都被 Akismet 过滤掉了,但每天都要看一眼里面有没有误伤的,是件很头疼的事情。

于是解决方案之一就是禁用 XML-RPC 形式的评论,我就不相信所有的垃圾评论都是通过网页发的。如果垃圾评论是机器自动发出的,那通过 XML-RPC 是最合理且高效的形式了。而普通读者则不会通过 XML-RPC 来发送评论。

如果你发现在本博客留言出现故障,请留言。

顺便说一句,禁用的方式,是在 functions.php 中加一句:

这样就禁用了匿名用户通过 XML-RPC 的评论,而本博客并没有开放注册,所有的评论都被认为是匿名评论,于是就等同于屏蔽了所有的来自 XML-RPC 的评论。

没有商业公司支持的开源软件就是一个笑话

这件事要从几个月之前博客升级到 Apache 2.4 说起。

7月份的一天,我发现 AWS 提供了一种新的机型,比我当时用的要便宜,而且性能更好。由于硬件的变动,AWS 不能提供无缝地迁移,一定要手动操作,于是我就计划着迁移一下。迁移之前我研究了一下所需的各个软件的最新版本,我有个习惯,新装系统的时候,都会装上最新版本的软件,我相信新的版本更安全,性能更好。博客所用的软件主要就是三个,其最新版本分别是:Apache 2.4、PHP 5.5 和 MySQL 5.5。

装软件嘛,没什么复杂的。

我事先调查了一下,最新版本和我当时用的版本之间的差别,主要是 Apache 2.4 和 2.2 的配置文件格式有比较大的差别,还有就是 PHP 5.5 中自带了 PHP-FPM,它其实也和 Apache 有关系。说到底也就是 Apache 的配置有比较大的改动,其它都正常。具体的改动这里不多说,详细的说明请参见《在EC2中安装 Apache 2.4、PHP 5.5 和 MySQL 5.5 并运行 WordPress》一文。

Apache 2.4 和 2.2 的差别(业界称为 breaking change)我就不抱怨了,这和下面要说的东西真是小巫见大巫了。它的差别大到了一个程度,使得目前 2.4 在全球的使用率只占了 Apache 全部的 10% 不到,而 2.4 第一版是在 2012 年 2 月发布的。一个发布了 2 年多的软件只有 10% 的使用率,Windows Vista 见到了也会乐开了怀。

差别很大不要紧,哥搞定了。

之后过了几个月,就是最近,公司给了一些员工福利,Google Cloud 的优惠。为了充分利用这些个优惠,同时也体验一下 Google Cloud,我就把博客整体迁移到了过来。

Google Compute Engine 所支持的 Linux 发行版有:RHEL 7、CentOS 7、SUSE 12、openSUSE 13.1、Debian 7、Ubuntu 1410等。和 AWS 不同的是,AWS 提供了一种称为 AmazonLinux 的系统,虽然它不是出自名门,但看名字是 Amazon 重点支持的对象,毫不犹豫就选了它。而 Compute Engine 没有类似的设定,于是我就把所有的版本都试了一下。接下来就说一下它们之间的异同。

首先是安装包的管理,RHEL 和 CentOS 用的是 yum、SUSE 和 openSUSE 用的是 zypper、Debian 和 Ubuntu 用的是 apt-get。这倒也没什么,虽然名字不一样,指令都大同小异,搜索一下 5 分钟就学会了。

接下来安装三大软件。装软件嘛,没什么复杂的。

之前在 AmazonLinux 上见识过,Apache 的安装包分为 httpd 和 httpd24,因为 2.2 过于流行,httpd 一直都被用于安装 2.2,那 2.4 只好用了另外的名字。回到Compute Engine 这一边,CentOS 的 httpd 直接指向了 2.4,表扬一下;RHEL 和 AmazonLinux 类似,只是 2.4 的名字是 httpd24-httpd,这也好理解,问题不大;而 Ubuntu 中的名字是 apache2,这也没什么;但是,SUSE、openSUSE和Debian 默认都没有带 Apache 2.4 的安装包,这…………。openSUSE 要升到 13.2 才有 2.4 的安装包,两年都没把 2.4 加入官方软件库,这算是几个意思。

于是我只剩下了四个选择,httpd24 和 apache2 各两个,于是我就都安装了一下。虽然它们都是 Apache 2.4,应该都是编译自相同的源文件,但是安装完之后的情况截然不同,httpd 装完是这个样子的(目录结构取自 tree -d,下同):

而 Ubuntu 的 apache2 是这个样子的:

openSUSE 中是这个样子的:

直接吓尿了。

由于 Apache 并不是装完就可以用,还要配置一大堆的东西,比如 vHost、SSL,还有和 PHP-FPM 的通信等等,我相信它们只是目录结构不同,配置方法还是大同小异的,但是我不想再重新走一遍当时 2.2 升 2.4 的时候的各种坑,于是果断选择了 RHEL 或者 CentOS。

另外还有一个问题是 PHP 5.5。由于 PHP-FPM 在 5.5 中才成为官方插件,并且只有 PHP-FPM 才能体现出 Apache 2.4 的 Event MPM 的效率。于是我非常希望在新的系统中继续使用 5.5 或后续版本。而因为这样,最终被迫使用了 RHEL。RHEL 7 是唯一一个满足我所有需求的版本。当然 RHEL 也有坑,就是 SCL,它和传统软件会产生兼容性问题,但想想这种方式长远来看也算不错,毕竟还有 Redhat 在背后支持,于是就用了。

当然,你可能会说这几个软件在第三方软件库中都能找到,那好,我找给你看。比如有个软件库叫“REMI”,貌似用的人还蛮多,但是,CentOS 的官方 wiki 把 REMI 列在了 “Known Problem Repositories”,就是“有问题的软件库”,而另一个软件库,webtatic,在 wiki 中就压根没有提到。CentOS 的 wiki 写得还蛮详细的,其它几个发行版连类似的 wiki 都没有。你说我敢用么。

事情还没有结束。

Compute Engine 提供了一个功能:startup script。意思是写一段 bash 脚本,放在比如 github 上面,然后在创建虚拟机的时候指定运行那段脚本,做一些自动化部署的工作。看上去蛮好用的一个功能,但实际用起来问题一堆。对,又是 Apache 的问题。

Apache 有自己的配置文件格式,扩展名是 .conf,github 上对应的格式是 apacheconf。这是一种纯文本的格式,类似 INI + XML,样例可以看之前的文章。而 Apache 官方并没有提供 API 来修改 .conf 文件,大家都只能用文本编辑器来手动修改。且不说这种方式效率差并且非常容易出错,问题是它没法写在 bash 脚本中啊。比如我要把 /etc/httpd/conf/httpd.conf 中的第xx行从下面这样:

修改成

肯定有人会嘲笑我不会用 Linux 中的工具,比如 sed。sed 是一个很强大的工具,它能以各种花哨的方式来替换文本内容,我看到过 stackoverflow 上各种答案都用它。但是,sed 固然强大,但它无法预知未来啊。现在 ServerName 是写在 httpd.conf 中的,万一它某一天被移到 servername.conf 中了呢?现在它叫 ServerName,万一之后被改成 HostName 了呢?不要笑,这些变动在 Apache 的历史上都发生过,难说之后不会再发生。

PHP 和 MySQL 也没好到哪里去,它们都用纯文本的配置文件,文件名、文件内容都根据 Linux 和自身的版本不同而不同。

虽然我可以花个几个月编写并调试出一份完美的 bash 脚本,但这也并不能保证它在未来的版本中继续可用。于是我就放弃了 startup script,依然手工配置了所有的东西。

各种问题都是小 case,哥都搞定了,博客继续稳定运行。

这段经验不禁让我想起一个视频,视频作者从 Windows 1.0 逐版本一直升级到 Windows 8,在 Windows 95 的时候装了一个游戏 DOOM 2,升到 Windows 8 之后,DOOM 2 还可以继续玩。

上述的各种软件和 Windows 比起来,就是一个笑话。