PHP-请教如何实现分布式验证码认证

PHP-请教如何实现分布式验证码认证

泛泛之交 发布于 2017-07-27 字数 321 浏览 1216 回复 2

大家都知道实时动态展现验证码是非常耗系统资源的,如果网站请求量很多会影响网站正常的应用。一般情况下我们都把验证码的展现、验证都跟应用放在一起。我想了解分布式的验证码认证实现方案。

应用场景,以下所有的域名都分布在不同的机房:
1、我的应用:login.abc.com
2、验证码服务:auth1.bcd.com auth2.bcd.com ……

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

归属感 2017-11-10 2 楼

因为“动态展现验证码”是需要事先计算动态生成图片(画背景、画干扰线、随机数字生成以及字体变形),所以大量用户同一时间验证,非常耗系统资源,刷验证码攻击更不用说。

解决方法:

1.预先生成图片,然后保存在验证码服务器的内存里(最好自己实现,方便的话直接用memcache),用户访问时随机映射到图片URL返回。
2.验证码图片一般不大,JPEG格式才4~5K。这样每次从"1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"挑选4个数字产生字符,共C37取4=66045种组合,也就是生成图片总大小258MB。占用磁盘空间不大的。
3.分布式可以用来扛流量,前端设置一个类似反向代理的服务器,随机重定向用户到后端架设的Lighttpd、Nginx服务器。

验证流程:

1.若服务器流量承受不了,可以把验证图片和验证码同时发到客户端(验证码需要加密),用户输入不正确,不用请求服务器,直接客户端脚本提示。其实不用做这么复杂,要刷验证码就让他刷,不停刷新网站还不是刷着。
2.前端反向代理打穿与后端服务器的会话,使用户一次验证始终对应一台服务器。
3若前端服务器重定向程序自己实现,可采用如下代码:

$servers=array('auth1.bcd.com','auth2.bcd.com','auth3.bcd.com');
$index=substr(microtime(),5,3) % count($domains);
$server=$servers[$index];
header("Location: http://$server");

注意这里没有采用类似CPU的轮转调度法,因为注意需要保存最后一次转移的服务器序号,而且转移序号需要上锁,这样请求的并发性将大大降低。

夜无邪 2017-10-21 1 楼

我赞成黄文彬说的预先生成图片的方式,这样能加快返回验证码图片的速度,降低服务器负载,在验证码服务器上,我们可以跑一个程序,定时更新这些图片。

另外在问题中提到的应用服login.abc.com跟验证码服auth1.bcd.com使用的域名是不一样的,我想说一下具体实现的方法:

1.首先我们建立一个auth1.bcd.com auth2.bcd.com的服务器集群,这个集群可以采用上面所述方法来对验证码图片进行维护跟管理,其中验证码的存储可以采用memcached来实现数据共享,前端访问可以设置一个反向代理的auth.bcd.com服。
2.具体使用时,在应用login.abc.com的页面上可以通过类似以下的代码:

<from action="" method="post">
<input name="r" type="hidden" value="132413244523">
<input name="code" type="text" value="">
<img src="http://auth.bcd.com/?r=132413244523" />  
<input type="submit" value="ok">  
</form>

其中r值是不重复的随机变量值,auth.bcd.com服在接到http://auth.bcd.com/?r=132413244523的请求后会返回相应的验证码图片并将r值跟验证码值记录到memcached中,login.abc.com程序验证时只要将用户提交的code值及r值通过auth.bcd.com的接口进行校验正误就行。