Stay Hungry.Stay Foolish.
谈谈可靠的验证码校验流程

前言

需要用到验证码的地方有很多很多,比如

  • 评论防刷
  • 登陆防爆破
  • 其它…

设计验证码的目的都是基于安全的考虑,但是很多时候看似已经加上了验证码,其实并没有什么卵用,因为设计流程有很大的问题。


错误的设计

其实这里有很多的坑,各种你想没想到的

我也曾经踩过一个,本以为自己设计的验证码肯定不会出现安全问题,结果被表哥测试了一把无情打脸。先说说我的那个坑吧,之前博客是用ruby on rails写的,然后写了个验证码,特么的测试尽然可以复用,我自认为验证码的设计流程肯定没问题。最后发现rails默认的session store尽然是cookies,怎么实现这个呢?简单的说就是用secret_key把session字段放到cookies里面的某个字段再加密,同时也可以知道泄露这个secret_key的后果,session任意伪造。。也就是说验证码也是放在cookies里面,所以抓下评论的请求包就可以重放(表单提交的验证码永远等于cookies解密的),这真的是一个大坑,我最后的解决方式是把session store方式改为了db。

还有一些我遇到的奇葩的验证方式:

  • 场景一:服务端在效验完用户提交的验证码和服务端保存的验证码是否相等之后,程序就返回了,可以导致重放。攻击者对提交表单抓包不断repeat就行,因为每次repeat都不会去请求一次验证码接口,导致没有被销毁的验证码一直保存于服务端。
  • 场景二:目标是防止使用别人手机来提交表单,所以会做一个表单,验证码设计采用ajax,提高用户体验,设计的时候正确的走完了验证码流程,看似没有问题,但是最后提交表单的时候没有做一个验证之后的bind,导致最后一步表单篡改为别的手机号,数据库最后插入的时候字段用的是表单提交的手机号,篡改成功,这个时候正确的方式是在使用ajax验证完之后服务端bind一个验证通过用户的手机号字段,插入数据库的记录取这个字段,无论攻击者如何篡改都没有。如果此处没有使用ajax,而是把验证码和其它所有字段都一起提交,在服务端同时验证手机号和验证码也可以避免这个问题,总结来说插入数据库的手机号总是取用户点击发送验证码请求的手机号值。
  • 场景三:这种就是完全用前端在做验证,是一个多页的提交表单,第一页里面有个手机号验证码效验字段,接下来的几页是否可以进行依赖第一页提交之后的返回值,大概就是js取到返回值,如果正确,则可以跳转提交,服务端仅仅只效验了验证码而忽略了手机号效验,然后插入数据库记录的手机号又取了表单提交的。攻击者提交表单篡改手机号为别人,然后只需要修改返回包或者懂js的直接修改js的值就可以进入下一步。
  • 场景四:就像我那个例子,属于对框架不了解,没有熟读框架文档。

正确的设计流程

下面我说下正确的设计流程,其实很简单

  1. 确保验证码会保存于服务端,db, memcached, redies都可以。
  2. 服务端生成验证码发送给客户端,同时服务端保存一份验证码值,用户点击提交表单后将服务端的验证码和用户提交的验证码做判断。
  3. 做完第二步的判断无论相不相等,销毁服务端验证码。

PS: 很多场景需要通过设计一个验证码发送给手机来验证手机号是否是本人的,这个时候切记必须同时校验手机号和验证码,记住插入数据库记录手机号总是取用户点击发送验证码提交过来的手机号,这一步就像TCP握手一样无法伪造,一伪造收到消息的对象就变了,所以取这个值是非常可靠的!

自由转载-非商用-非衍生-保持署名(创意共享3.0许可证
评论
2016-11-24 10:15:31

我就是这么屌

2016-11-24 10:16:04

' or 1=1 --

2016-11-24 10:17:01

@‘ or 1=1 -- ' or 1=1

2016-11-24 10:26:45

我屌不屌

2016-11-24 10:28:13

<script>alert("hello world")</script>

2016-11-24 10:30:06

&lt;script&gt;alert("hey")&lt;/script&gt;

2016-11-24 12:02:56

感觉楼上好欢乐~

2018-06-30 20:43:15

Priligy Eczanelerde <a href=http://cialviag.com>generic 5mg cialis best price</a> How To Buy Cialis 5 Mg Amoxicillin For Fish Price