工作笔记 - 改进的验证码验证方案

75 阅读5分钟

概述

在很多互联网业务系统中,为了防止各种机器人和自动化程序的攻击,需要在系统认证操作过程上使用验证码来实现一个二次验证机制。常见的附加验证方式,包括captCha和sms短信验证码等等。从逻辑上来说,它们都是一样的,就是使用一个外部机制生成一个验证码,然后需要用户在前端人工输入并且验证这个代码,来确保这一操作应当通过人为而非程序自动化的,来提升系统安全性。

关于captcha和sms的具体实现不是本文要讨论的内容,我们只需要假设有一个机制能够生成一个代码(所谓的图形验证码或者短信/邮件验证码),用户使用外部方式渠道获取这个信息(目视识别、短信或者邮件),并且在认证界面手动输入这个信息参与验证过程。

针对这个过程和需求,传统的实现方式通常是将这个验证码临时保存在服务端的存储(如redis)或者session信息中。然后在认证的时候,将验证码从redis或者session中取出,并且和用户输入的信息来进行比较确认。笔者原来维护的一个系统就是使用这种实现的方式。但笔者认为,这个技术方案以下几个缺陷和不足:

  • 引入了redis作为临时存储,增加了系统复杂性和故障点,以及部署和运维的工作量
  • 使用session管理认证会话,有一定安全风险(特别是如果没有使用https协议)
  • 信息的集中存储和访问,对网络和系统性能有一定要求
  • 所有的信息验证都在后端完成,如果网络性能不佳,会影响用户的操作体验
  • 验证码生成、传输和处理等各个环节紧密耦合,不利于维护、升级和扩展

针对以上问题,笔者在本文中提出了一个改进的技术方案,在合适的使用场景中,可以消除和改善上述问题。

基本过程

笔者提出的技术方案,其基本过程和原理如下:

1 验证码生成,可以是一个外部过程,认证模块只需要获得生成的结果,并基于用户输入进行验证,所以在本技术方案中,原始输入是来源于验证码系统生成的结果,比如一个6位数字(ACODE)

2 用户请求认证,系统在生成验证码(展示图片或者发送短信)的同时,响应给用户一个用于验证的附加信息

3 此信息包括三个部分的内容: 时间代码(TM),客户端验证信息(CA)和服务端验证信息(SA)

4 TM表示此验证操作发起时间,可以用于验证有效时间

5 客户端验证信息,可以在客户端完成用户输入验证码是否正确

6 服务端验证信息,用于验证最后提交到服务端的信息的正确性,

7 用户看到或者得到验证码,在认证界面中输入原始代码并提交

8 客户端在真正提交到服务端接口前,先对这个输入代码进行验证(客户端验证)

9 客户端验证通过后,对提交信息进行重新组合,成为在服务端可以验证的信息,真正提交给服务端

10 服务端对最后的组合信息进行验证,包括信息的完整性和时间的正确性(避免重放攻击)

从这个基本过程和原理我们可以发现,这个过程的核心,就是对客户端验证信息和服务端验证信息进行合适的编码。编码的方式,可以使用密码学操作中的摘要技术,这样可以对信息进行验证,同时保证无法从摘要信息获得原文。

所以,本方案中,选择的算法包括:

CA = hmac( ACODE, CLT_KEY + TIME );

SA = hmac( TM + hmac(ACODE, TIME) ,SRV_KEY + TIME);

上述算法相关元素和说明,后面在参考实现环节有更详细的探讨。

参考实现

基于以上构想,相关的可执行的参考实现代码如下:

读者可以运行并且理解这个过程,这里简单说明一下:

  • 完整模拟实现了设计的各个流程
  • 参考代码是纯前端代码,无需外部依赖,而且Nodejs后端适配也非常简单
  • 算法核心是改进的HMAC算法,基于crypto.subtile模块,需要HTTPS支持,如果在HTTP环境中使用,需要第三方库
  • SRV_KEY是服务端密钥,需要在服务端保密,其作用是对构造信息进行签名,并确保信息的完整
  • CLI_KEY是客户端密钥,本身并不机密,主要目的是统一算法操作(HMAC),同时提高一些安全性
  • 真实使用的密钥都是随时间变化的,而且基本上所有信息都是动态的,安全性更高
  • 可以按需进行认证有效时间验证

优势分析

从实现代码来看,和原有方案相比,本文提出的技术方案有以下特点和优势:

  • 基于密码学原理,无需外部系统支撑,大大简化部署、运维和扩展
  • 基于计算而非IO来提供处理性能,可以快速提升或者改进
  • 加入前端验证,提升用户体验,并减少无效验证请求
  • 方便横向扩展(多服务器共享服务端签名密钥即可)
  • 方便支持如captcha、sms、email、otp等多种补充验证方式

小结

在本文中,笔者针对传统应用程序中,验证码的实现和操作的一些不足和缺陷,提出了一种基于密码学算法的改进技术方案。文中描述了其基本原理和过程,并给出了相关参考实现代码。