不使用图片的验证码方式

snap0016_captcha 验证码是防止被机器人恶意灌水的一个方法,产生一个只有服务器才知道的信息(例如一个单词、数字等),在客户端浏览器中以机器人不能分析的方式(通常是图片)出现,作为判断机器人和真人的一个依据。一般是在服务器端生成图片,由用户在文本框输入看到的文字。 使用生成图片方案的缺点在于:
  1. 在服务器端生成图片比较耗费资源。虽然有一些优化的办法,例如先一次性生成一批图片,然后缓存,用户看到的图片其实不是实时产生的,但这个方案存在被破解的风险,生成时也需要占用一些资源。(如果是测试服务器先生成,迁移到生产服务器,虽然不占资源,但是系统却复杂了)
  2. 理论上来说,机器人很难辨认的文字,用户也很难辨认,这个方法在安全性和易用性之间存在矛盾。
Kevin LE 提出了两个不需要生成图片的验证码方法演示): ### 第一个比较有趣,利用和用户交互的办法:
  1. 服务器端产生一个真正的密钥,凭借这个密钥,才能提交成功。但不将这个密钥随HTML一起直接发到客户端,而是先给客户端一个随机产生的数字(Secret Number,简称SN)。
  2. 客户端拿到SN,表现成一个小题目,需要用户拿鼠标去拖拉一下:将滑动条移动到这个数字代表的位置。当用户拖动到正确的位置时,浏览器就向服务器发送一个获取验证码的ajax请求,这个请求包含了用户拖动条的位置。
  3. 服务器端接收到客户端的Ajax消息,验证拖动条的位置是否正确,如果正确,发送回真正的验证码。
  4. 客户端接收到真正的验证码,自动存到表单中。用户提交时,连验证码一起提交到服务器。
这个方法巧妙地用交互的方式分辨人与表单机器人,比艰难地分辨图案要好玩很多,并且运算的压力转移到了客户端,解放了服务器。而且SN的交互方式还可以做得更加好玩、简单,例如“把时针拨到5点”、“点击水果里面的西瓜”……就看大家的想象力了,谁曾想过,原来验证码功能也可以这么好玩呢? 也许用户在注册、登录的时候都是一种享受。 不过这个方法也有安全性隐患,虽然在用户看来,验证码是拖动了才能得到的,但从技术角度来看,得到这个验证码并不需要进行机器人做不到的交互,可以用程序方法破解出来:从前端HTML分析出SN是很容易的,然后做一个假的 ajax 请求,服务器分辨不出这个ajax是用户真正发送的,还是机器人发送的,于是真正的验证码就暴露了。 有什么方法可以改进吗?我还在想,不过太笨了,想了几个都不行,所以暂时还没想出来,想到了一个,期待与大家探讨。 放若干张图片,让用户从中挑选出一张符合条件的图片。举例,放四个不同的人物照片,然后问用户:哪个是这四个里面 最高的/最年长的/男性的/最开心的/…… 等等,题目是随机的,照片也是随机的。这样就解决了SN暴露的弱点,又能保留好玩的感觉。有点类似这个: http://www.captcha.net/cgi-bin/esp-pix