当前位置:首页 > 问答 > 正文

验证码放Redis里更安全点,避免泄露和重复验证的烦恼

行,那我直接给你把那段关于“验证码放Redis里更安全”的内容搬过来,这是之前一位网友在技术社区里分享的观点,讨论的是为什么用Redis存验证码比用数据库或直接返回给前端更好,他讲得挺直白的,我尽量原话复述。

他说,最开始做登录注册的时候,很多人图省事,验证码生成以后,要么是直接塞到返回数据里给前端,让前端在提交表单时再原样传回来;要么就是往数据库里插一条记录,跟前端返回的验证码字符串做个比对,但这两种方法,毛病都不小。

(来源:原话提到“直接返回前端”的做法) 如果是直接返回给前端,那风险就太大了,验证码这玩意儿,本来就是为了验证操作的是你本人,结果你把它明晃晃地放在网络请求里传来传去,万一哪个环节被截获了,比如有人用了不安全的网络,或者APP被抓包了,验证码就直接泄露了,攻击者拿到这个验证码,在有效期内就能冒充你完成操作,那这个验证码就形同虚设了。

(来源:原话提到“存数据库”的做法) 那存数据库总行了吧?比直接传是好点,但也很麻烦,验证码一般都是有时效性的,比如五分钟或者十分钟有效,时间一过,它就是废码了,如果你存在数据库里,你就得写个定时任务,隔一段时间就去扫描一下表,把过期的验证码记录删掉,不然这张表就会越来越臃肿,全是垃圾数据,这个定时任务本身也是个负担,搞不好还会影响数据库性能,每次用户提交验证码,你都得去查询一次数据库,验证完了还得把那条记录标记为已使用或者干脆删除,这增加了数据库的读写压力,对于高并发的场景,比如秒杀时发验证码,数据库很可能就扛不住了。

验证码放Redis里更安全点,避免泄露和重复验证的烦恼

这时候,用Redis的优势就体现出来了,他解释说,Redis是一种内存数据库,数据主要放在内存里,所以读写速度极快,比去硬盘上读写的传统数据库快好几个数量级,这对于验证码这种需要快速验证的场景非常合适。

(来源:原话详细解释了Redis的几个关键特性如何匹配验证码需求) 他接着说了Redis特别适合存验证码的几个地方:

验证码放Redis里更安全点,避免泄露和重复验证的烦恼

第一是自动过期,Redis可以给存的每一条数据设置一个生存时间(TTL),比如你设置验证码有效期是300秒,那么当你把验证码存入Redis时,直接设置一个300秒的过期时间就行了,时间一到,Redis会自动把这条数据删除,你完全不用操心后续的清理工作,这比用数据库自己写定时任务要优雅和高效得多。

第二是天然防重复,Redis的键(Key)是唯一的,通常我们会用一些唯一性的标识作为Key,用户手机号:业务场景”(13800138000:login),然后把生成的验证码作为值(Value)存进去,当同一个手机号在验证码有效期内再次请求时,你只需要用同样的Key去存新的验证码,Redis会自动覆盖掉旧的值,这样一来,对于用户来说,他永远收到的是最新的验证码,旧验证码自然就失效了,从根本上避免了同一个验证码被多次使用(重复验证)的风险,如果你用数据库,还得先查询一下有没有未过期的旧记录,逻辑就复杂了。

第三是高性能与原子性,因为Redis是单线程模型(指处理命令的核心模块)且基于内存,处理命令非常快,执行“设置值+设置过期时间”这样的操作是原子性的,可以一条命令完成,确保数据的一致性,在高并发下,用户提交验证码进行验证时,查询速度极快,体验流畅,不会因为验证环节慢而卡住用户。

(来源:原话最后做了个总结对比) 所以他的结论是,相比于传统方法,把验证码放到Redis里,一方面通过自动过期和内存存储解决了“垃圾数据清理”和“性能瓶颈”的烦恼;通过唯一的Key设计和原子操作,更好地防范了“验证码泄露后被复用”和“并发请求导致的数据错乱”等安全问题,说白了,就是既省了程序员的事,又让整个验证流程更坚固、更安全,他也补充了一句,保证Redis服务器本身的安全和稳定是前提,如果Redis宕机了,那所有依赖它的验证就都失效了,所以通常需要做高可用方案,对于验证码这种短时效、高频率的数据,Redis是目前最主流和最合适的选择。