今天上午照常来博客中查看状况,结果发现博客的评论遭遇了垃圾群发,评论中充斥了大量垃圾信息,骂了句 TMD! 然后写代码,解决该问题。
由于一些商业利益的驱动或者其他原因,市面上和暗“道”中存在不少所谓商机群发软件,能够自动向带有留言板、文章评论、论坛等功能的网站发布广告,内容五花八门:色情、枪支、毒品、垃圾小广告、网站链接、赚钱机会等。无节制的恶意群发,影响用户对网站的正常使用体验,也很大程度上降低了系统性能增加了维护成本。所以大大小小的网站都会采取一些手段,来想办法阻止这种群发软件发布垃圾信息。而其中最常用的手段,也是大家最烦的:验证码。
验证码的基本行为就是在页面上显示一些随机数字字母,然后让用户识别并填写好,点击提交按钮的时候这个码随正常的表单 (form)数据一起提交到服务器端,然后服务器端通过判断这个验证码是否被正确填写,来决定是否按照正常流程处理数据。验证码,大部分情况是有效的,但是太过简单的,或者纯客户端的所谓验证码技术,就很容易被群发软件破解并自动填写。所以,验证码开始做的更加复杂化:字体扭曲变形、添加大量不规则噪点或噪线、甚至使用带有吵杂背景的语音朗读,让用户辨别 …… 用户在这个过程中变得越来越痛苦,因为相当多的验证码已经扭曲到几乎无法辨认啦,而且变得相当长了。那些用数学题之类的“智商”验证码,则更让用户的关注点变了——忙活完验证码之后,大概也已经忘记了自己到底来干啥的了。
我们就没有什么好办法解决这个问题吗?
- 首先,作为有情怀的开发者,应该尽一切可能减少对用户正常行为的干扰,所以类似于验证码的手段都不应该考虑。
- 然后,静下心来想想如果你是个群发软件的“作者”,你会怎样做?这个群发软件的操作行为是怎样的?什么地方会是明显不同于正常用户操作的地方呢?
- 最后,写代码尝试阻止前面发现的机器人行为。
这里,说说我在本博客中所使用的方法吧:
- 首先,总结并验证群发软件的基本行为:
用代码直接发起一个 request 到网站页面中,然后寻找可以 post 的 form (尤其是带有评论、留言、回帖等文字信息的),再用 form 中所有表单域的 name 伪造一个 post 的数据,向 form 的 action 属性所指定的页面发起伪造的 Post 请求。重复上述的流程即可实现重复的群发。网速足够快的时候,一秒钟内发布 10 条 8 条应该没问题。 - 了解了前面的群发软件基本行为,那么我们会发现其中的一些可用的关键点。比如,为了能够快速群发,软件通常会简单快速的分析 html 代码并伪装要 Post 的数据,也就是说它会缺失一些正常用户在用浏览器打开页面时的行为。比如:执行 js 脚本!
- 既然通常群发软件不会去执行 js,而用户打开网站,浏览器会自动执行 js。那么我们就先用这个来解决基本问题。在表单中创建隐藏字段,然后不要在页面生成的时候直接填写进去,而是用 AJAX 手段异步的从服务器端获取一个随机的码,然后当用户提交表单的时候,就会将这个码一起提交到服务器上。剩下的跟验证码的验证机制就一样了,在这里就不多累述。
- 基本问题搞定了,那么是否万事大吉了呢?高级别点的群发软件,会通过动态的 Browser 控件或者是浏览器插件的形式来实现群发,那么也就是说它存在了浏览器执行脚本的过程,那么上一步中所说的方法就存在失效风险了。怎么办?
- 我们还是要分先机器与人的区别,正常的用户在填写评论时,通常会一项一项的填写后,再提交,这是需要一定时间的;而群发软件为了群发的量和速度,软件行为上则会很着急——尽快封装数据然后提交。基于这一点,我们只需要用
setTimeout
,让前面的 AJAX 获取随机码的过程延迟 3、5 秒再执行,就可以防范“急不可耐”的群发软件了。
本站用上述的思路做了验证机制,对正常用户来说这个验证过程是“不存在”的,群发软件则被阻止掉了,世界一下子变的清静了 :)