序
验证码,只要一点简单的逻辑,就能避免泱泱脚本大军的骚扰。但利剑往往是双刃的,并不是每个场景都适用,本文将通过记录一起线上事故,来展示使用图形验证码的代价,并讨论如何应对类似情况。
科普一个冷知识:验证码的英文是CAPTCHA,是Completely Automated Public Turing test to tell Computers and Humans Apart的缩写,翻译过来是“全自动区分计算机和人类的图灵测试”(不是“雅木茶”)。
事故过程
一切都要从一个简单的需求说起
公司新游戏即将上线,运营已经激动地搓手手了,于是一次预约活动规划了下来。就是那种输入手机号和手机系统的预约活动。这个需求太简单了,开发也没多想,一梭子代码就下去了。唯一一层防护是为了避免脚本刷接口,要求预约时要输入一次图形验证码。
悲剧即将上演
倒计时3,2,1,活动开始。开始的时候一切顺利,流量流入,预约数据也在有条不紊地入库。不过一会儿,客服就开始忙活了起来,原来大量玩家反馈:本该显示图形验证码的地方现在正显示着一个x。于是,一句”你们公司用的是土豆服务器吗“刷遍了微博贴吧。
开始思考
这是图形验证码的一般做法
- 在img标签的src填入生成验证码地址,该接口会在内存中生成一张图片。严谨一些的话,还会在图片上面打上干扰线和噪点。
- 将验证码存入Session后,返回图片。
- 用户提交数据,比较参数和Session值。
天底下没有理所当然的事
这本来是最正常不过的操作,但仔细过一遍可以发现,生成一张图形验证码的代价是很大的。
- 生成图片,占用比普通操作更多的内存
- 生成随机数、噪点、干扰线,需要生成随机数
- 图片传输,占用带宽
- 验证码读取\写入Session,需要读写磁盘
实践一下
代码
写一个简单的验证码生成方法:
$str = "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVW";
$len = strlen($str) - 1;
$code = '';
for ($i = 0; $i < 4; $i++) {
$code .= $str[mt_rand(0, $len)]