和 Akismet 说再见

一个多月之前我开发了一个微型的垃圾评论防御插件,试用了一个月之后,没有一条漏网之鱼,于是很放心地把 Akismet 给删掉了。

Akismet 是一款很棒的工具,但和垃圾评论的对抗就像抵御疾病,没有一种万能的药。垃圾评论工具会不断进步,就好比细菌产生了抗药性,必须有一种新药才能治愈它。Akismet 尝试使用一种统一的方式来解决所有的垃圾评论,必然会导致系统慢慢变得复杂、性能下降。对于小型博客来说,没有必要用牛刀来杀鸡,于是我就写了一个小插件来解决这个问题。

如果你也感兴趣,也可以尝试创造自己的药物来对会垃圾评论。

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

上一篇提到我把 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. 这个机制有多么有效?
目前已使用超过48小时(至 11 月 28 日),没有一条垃圾评论漏网。

全站禁用 XML-RPC 评论

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

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

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

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

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

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

与时俱进的垃圾评论

和垃圾邮件一样,博客中的垃圾评论也是一种 SEO 的方式。它的主要特点是包含一些网页链接或者关键词,以达到做广告的效果。Wordpress 有一个很好用的官方插件叫做 Akismet,它把所有的评论都发送到 WordPress 的官方服务器,来鉴别每条评论是不是垃圾评论。这样做的好处是一旦某一种模式的评论,如果包含某个特定网址,被认为是垃圾评论,那么它将在所有的 WordPress 站点中被阻止,总体上提升了垃圾评论的识别率。

我一直都在使用 Akismet 来阻止垃圾评论,不过在上周发生了一点小小的意外。

意外的根源来自我的一个邮件通知评论作者的插件,那是我一个月前刚刚启用的新功能。它的作用是在有人回复了某条评论时,自动给他所回复的人发送一封邮件,以便提升“回头率”。之前一直都工作得很好,我也没有仔细维护它,直到上周,一些读者开始抱怨收到了垃圾评论的通知邮件。

一开始我认为是 Akismet 的问题,因为确实有一些垃圾评论没有被过滤掉,然后我就手动把那些评论标记成垃圾评论。但在这之后,又收到了很多类似的通知邮件。这让我很纳闷,因为垃圾评论已经被 Akismet 给过滤掉了,不应该再触发通知功能。

后来仔细研究之后才发现,原来从一开始,垃圾评论就会触发通知功能,但始终没有人收到这些通知。原因是,那些垃圾评论没有回复给其它评论者,他们都是直接回复博文的评论。由于没有回复人,邮件就不会发出去。但是不知为何,垃圾评论的功能升级了,它开始回复已有的评论。由于我的插件中没有做好检测,尽管这些垃圾评论被 Akismet 过滤掉了,但依然会有通知邮件。

现在邮件通知功能已经改进了,不会再对垃圾评论发送邮件了。如果还有问题,请及时留言。