如何控制网站垃圾留言

个人网站的表单留言功能一般用于与访客交流,有多种成熟的垃圾评论管理方法可供选择,如reCaptcha、Akismet插件,甚至直接使用第三方评论交流工具。然而,对于一些企业网站,尤其是产品推广类网站来说,表单通常用于获取客户询价,是访客转化的重要工具,网站管理员在对待这些垃圾留言管理上通常非常谨慎。 不幸的是,很多提供留言功能的企业网站每天都接受大量的垃圾留言,一些企业的信息系统中,正常的信息甚至都被淹没在垃圾信息之中,大量的精力被浪费在处理这些信息上。

垃圾留言

垃圾留言

这逼得企业不得不采取措施,如增加验证码、使用关键词屏蔽、网址屏蔽功能、留言评级插件等。但这里会有几个问题,一是增加验证码会增加操作复杂度,很多企业不希望给客户制造难题,以免劝退他们;二是网站咨询本身都有限,担心一些关键词屏蔽或评级插件误伤正常留言,从而遗漏商机。

针对这一情况,我之前的做法是控制不让发重复信息,控制一条信息内链接的数量,同时增加灰名单功能。在灰名单内包含关键词的留言一律放到垃圾箱内,而留言中包含黑名单的内容则直接拒绝,这能屏蔽掉一些有特征的垃圾留言。

垃圾留言控制后台

垃圾留言控制后台

然而,仍然有不少漏网之鱼,他们要么是纯垃圾信息,要么是各种推销信息。每天研究他们提取屏蔽关键词也是一个浪费生命的工作。如何以低成本、一劳永逸的方式解决这些问题成为了不得不做的事情。

实际上经过分析,可以发现,这些垃圾留言都是通过爬虫发布的。一些不良爬虫在爬取网页之后,分析得出网站提供表单功能,然后自动往action地址发送数据。所以可以推测,大部分垃圾留言都不是通过浏览器发送的。那么是否可以通过User-agent白名单实现屏蔽呢?肯定不行,破坏者不会连User-agent伪装都不懂。

那么使用浏览器和不使用浏览器有什么区别呢?最主要的区别就是对页面信息的处理。试想一个访客来到一个包含表单的页面之后,浏览器会首先加载此页面的HTML代码,然后解析加载页面上的其他资源(图片、视频等等),最后渲染成可视画面。而爬虫通常则不会加载其他资源,只是分析页面的HTML代码。

基于这一点,我们可以做一些操作。当浏览器解析页面时,在某个请求中给浏览器写入一个cookie。浏览器请求其他资源(包括提交表单)时都会在请求中加上此cookie,而爬虫通常则不会。我们在表单处理程序中加入检测cookie的程序,就可以很好地对这些垃圾信息进行防护。

具体实现方法如下:

1. 在所有页面上增加一个Javascript,向后端服务器发送请求。如果使用CDN,必须保证此请求回源。如果有其他每次都要回源的请求,也可以公用。简单代码可以如下:

<script>
    new Image().src = '//example.com/getcaptcha.php';
</script>

2. 后端接受请求,并根据情况为客户端设置COOKIE。如果有需要,可以加密以便进行更复杂的校对。示例代码如下:

<?php
header('Cache-Control: private, max-age=3600');
header('Content-Type: image/gif');
if (isset($_COOKIE['domai_captcha']))
    setcookie('domai_captcha', time(), time() + 36000);
echo base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
?>

3. 在表单处理程序中进行处置。示例代码如下:

<?php
if (!isset($_COOKIE['domai_captcha'])) {
    header('HTTP/1.1 403 Forbidden');
    die('禁止提交,非法访问');
}

//下面是表单处理逻辑
?>

当然,这只是逻辑实例代码。具体业务实现可能会更为复杂。

同时,大部分网站都使用CMS进行管理。改变源代码的方式并不优雅。较好的CMS如Domai CMS、WordPress都可以通过接口的方式实现。例如,Domai CMS可以在functions.php文件中进行以下编写:

<?php
function _modify_feedback($request) {
    //不让没有获取COOKIE的爬虫直接提交表单,防止爬虫
    if (!isset($_COOKIE['domai_captcha'])) {
        return new DM_Error(__('Message Not Sent', 'aishred'), __('Unauthorized Request, Please Use Your Browser to Access and Enable Javascript!', 'aishred'));
    }
    //下面还可以对数据进行扩展,处理前台有很多后端未定义的表单名的情况
}
add_filter('pre_submit_feedback', '_modify_feedback');
?>

有聪明的读者可能会想到,我一个访客都不想错过,如果有访客浏览器没有启用Javascript怎么办?很简单,可以使用noscript标签:

<noscript>
    <img width="1" height="1" src="//example.com/getcaptcha.php" alt="">
</noscript>

通过以上的操作,我们成功地减少了90%以上的垃圾留言。其他的通过后台IP屏蔽、手动管理等方式,工作量大大减少,访客无感,信息无遗漏。当然,上述代码只是逻辑实例代码,具体业务实现还需更为复杂的处理程序。
以上方式只是一种参考,无法屏蔽上述描述情况之外的攻击。一旦攻击者了解网站防护逻辑,可能导致灾难性后果,请综合考虑,本人不对任何后果负责。