短信验证码登录接口,如何防止恶意攻击

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 该文讨论了移动应用中常见的手机短信验证码登录方式,后端实现通常涉及两个API:获取短信验证码和短信验证码登录。在设计时,为增强短信验证码接口的安全性,提出了几种无需使用Redis等存储介质的方案:1) 使用数字签名,基于时间戳或随机数生成唯一签名进行验证;2) 基于时间的有效期验证,通过加密或修改时间戳形式确保安全性;3) 应用TOTP算法,按时间生成动态码进行比对;4) 利用JWTToken生成带有限期的签名进行验证。这些方法旨在防止恶意攻击并优化登录接口性能。

 

 

现在市面上的移动应用通常都支持手机短信验证码登录(下文称“短验登录”),对于终端用户来说,这是比较便捷的登录方式。

短验登录的交互很简单。前端页面 输入手机号,点击获取手机短信验证码,然后输入收到的短信验证码,点击登录,完成应用的登录。

那么,对于后端程序,不外乎提供2个API。一个是获取手机短信验证码接口,一个是手机短验登录接口。

 

再具体一些,后端这2个接口,我们来设计一下。

1)手机短信验证码接口,/getSmsCode。 入参是 手机号,返参 主要是一组 code/msg。

正确返回示例:{"code":200, "msg": ""};错误返回示例:{"code":500, "msg": "用户不存在"}

程序逻辑是 先验证手机号在系统里是否存在,不存在直接返回code为错误码。手机号存在后,会执行一些防盗刷或限频策略,然后,利用一定算法生成一个6位数的一次性动态码,以手机号作为key设置redis缓存,然后向手机号发送短信,返回 code=200 的正常响应。

2)手机短验登录接口,/smsCodeLogin。入参是 手机号、短信验证码,返参 除了 code/msg 外,还包括 认证令牌以及用户的关键属性。

正确返回示例:{"code":200, "msg": "", data: {"token": "eyQDs7zYqbu.tW27Tgbdsad092x.2dSec","user": { "username": "菏泽树哥", "sex": "M"}}};错误返回示例:{"code":500, "msg": "验证码错误"}

程序逻辑是 以手机号为key读取redis缓存,验证 入参短信验证码 是否与缓存一致,不一致直接返回code为错误码。验证码一致后,获取用户信息,保存登录会话,生成登录认证令牌,返回 code=200、认证令牌以及用户的关键属性。

 

关于 getSmsCode 的安全防控,我曾经发文写过短信验证码接口防恶意攻击短信防盗刷策略

OK,接下来,我要说的是,从软件系统安全层面来考虑,如何保证 smsCodeLogin 的安全。就是说,如果我们单单按照上面设计的 短验登录 来实现我们的代码逻辑,那么,当恶意攻击者 伪造入参数据,不断攻击我们这个接口,我们岂不是一直持续不断地访问redis?

 

这显然不太好。

 

那么,从程序设计的角度,如何优化 短验登录接口 呢?

 

大家很快能想到一种方式, 手机短信验证码接口 多返回一个 key,后面请求 手机短验登录接口 时,携带这个 key, 服务端程序先校验key,key校验通过后,才走后续 手机短验登录 逻辑。

思路是对的。

那么,这时,在你的mind里,应该会有一个问号:手机短验登录接口 如何识别这个 key 的合法性呢?

让服务端保存 key 吗?保存 key 岂不是依然绕不开 redis 等中间件吗?(注意:我的前提是:服务端程序是集群部署,单点部署是可以不用redis的)

 

那么,该怎么优化呢?

只要思想不滑坡,办法总比困难多。

 

下面,我来介绍几种无需依赖redis等存储介质的方案。

 

🍀第1种方案我一说你就懂。

我们在外部系统接口对接中常用的方案————数字签名。

再详细一点来讲,签名由getSmsCode 接口 返回。然后, smsCodeLogin 接口去验签。

设计要点是要尽可能保证每次的签名都不一样。那么,可以基于时间戳或随机数或UUID串来生成唯一签名。也就是说,这种方案,需要引入2个参数:s,表示参与签名的唯一标识,值可以是时间戳或UUID串,t,表示数字签名,程序利用MD5算法基于s和服务端秘钥(或再加上手机号、验证码等参数)生成摘要字符串作为签名。

 

🍀第2种方案,我介绍一下。

基于时间。

通过 getSmsCode 回传一个时间戳 timestamp,取参数名为s。然后在 smsCodeLogin 里 直接去与当前时间戳做等值比对?显然是行不通的。毕竟,从 获取验证码 到 用户输入验证码 到确认登录,这是有时间差的。怎么办?

那么,我们就让timestamp在一个有效的区间内呗。例如,currentTimestamp - s ≤ 90s。

不过,你传一个明文的 timestamp, 那就是司马昭之心了,达不到安全防护的作用。因此,要对时间戳做文章。例如: 可以让 timestamp乘以一个约定的数字,例如312。再例如:对 timestamp 加密。从而,起到混淆的作用。

 

🍀第3种方案,还是基于时间。

在双因子登录的技术里,有一种基于时间生成动态码的开源算法TOTP。这个算法同样会考虑预留给用户足够的操作时间。它生成时间的算法是 T = floor(currentTimestamp / step)。其中,currentTimestamp 为当前的时间戳,单位为秒,step 为步长,双因子登录技术里一般为 30s 比较合适,floor 为向下取整。通过这样计算出来的 T 值,在一定时长内会保持一致(比如 00:00 ~ 00:29 为 1,00:30 ~ 00:59 为 2),每 30 秒便会自增。

据此, 对于短验登录的场景,我们设定 step=90s。那么,getSmsCode 返回 t。smsCodeLogin 用同样的算法生成T,与t进行等值比对即可。

 

🍀第4种方案,借助JWTToken。

首先,服务端保留加密key。然后,在用户请求验证码时,服务器生成一个 JWT ,取参数名为s,并将其发送给用户。smsCodeLogin接口里,验证 JWT 的有效性,包括验证签名和有效期,有效时才允许用户登录。

设计要点,同样是保证每次的token不同。这个就比较简单了,就像第1种方案里提到的那样,用 timestamp 或 UUID都行。另外,要为token设置有效期如90s。

多说一句,大家知道,JWT由header、payload和签名三部分组成,其实 getSmsCode接口返回的s,可以只返回JWT的payload和签名,不需要返回header部分。这样可以进一步达到混淆的目的,至少不能一眼识别出来s的参数值是个JWT。这会影响服务端校验?不会的,思考一下,你有办法的。

 

 

还是那句话,只要思想不滑坡,办法总比困难多。

你还有哪些方案呢?欢迎交流。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
7月前
|
存储 JSON JavaScript
前后端分离项目知识汇总(微信扫码登录,手机验证码登录,JWT)-1
前后端分离项目知识汇总(微信扫码登录,手机验证码登录,JWT)
189 0
|
7月前
|
前端开发 安全 Java
SpringBoot 实现登录验证码(附集成SpringSecurity)
SpringBoot 实现登录验证码(附集成SpringSecurity)
419 0
|
4月前
|
存储 NoSQL 数据库
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
这篇文章讲述了在分布式微服务系统中添加用户注册和登录功能的过程,重点介绍了用户注册时通过远程服务调用第三方服务获取短信验证码、使用Redis进行验证码校验、对密码进行MD5加密后存储到数据库,以及用户登录时的远程服务调用和密码匹配校验的实现细节。
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
|
2月前
|
Java
Java 登录输入的验证码
Java 登录输入的验证码
30 1
|
2月前
|
C#
C# 图形验证码实现登录校验代码
C# 图形验证码实现登录校验代码
84 2
|
3月前
|
存储 JSON 前端开发
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
本文介绍了在Node.js中使用token实现前端验证码和登录功能的详细流程,包括生成验证码、账号密码验证以及token验证和过期处理。
52 0
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
|
4月前
|
资源调度 JavaScript API
nest.js + sms 实现短信验证码登录
本文介绍了在Nest.js框架中集成短信验证码登录的实现方案,详细阐述了使用阿里云短信服务的配置流程、资质申请、短信模板设置,并提供了API调用示例和工程代码的运行步骤。
nest.js + sms 实现短信验证码登录
|
4月前
【Azure 环境】中国区Azure B2C 是否支持手机验证码登录呢?
【Azure 环境】中国区Azure B2C 是否支持手机验证码登录呢?
|
7月前
|
安全 Java 数据库
SpringSecurity实现多种登录方式,如邮件验证码、电话号码登录
SpringSecurity实现多种登录方式,如邮件验证码、电话号码登录
1284 2
|
7月前
|
缓存 算法 NoSQL
短信验证码登录接口,如何防止恶意攻击
该文讨论了移动应用中常见的手机短信验证码登录(短验登录)的安全设计。后端通常需要提供获取短信验证码和手机短验登录两个API。为了增强机短验登录API的安全性,提出了几种无需依赖Redis等存储介质的方案:1)使用数字签名确保请求合法性;2)基于时间戳的验证,允许在一定时间范围内有效;3)应用TOTP算法生成动态码进行验证;4)利用JWTToken进行身份验证并设置有效期。文章强调了创新思考在解决安全问题中的重要性,并鼓励读者分享更多方案。
581 1