短信验证码在 服务器 端的处理

转载:http://blog.sina.com.cn/s/blog_80a6423d0102wm74.html

目前,很多网站或app都要求用户用手机注册,比如滴滴打车的注册界面是这样的:

论短信验证码在 服务器 端的最佳处理姿势

 

流程大体分两步:

  1. 用户输入手机号,点击“获取验证码”(滴滴界面上叫“验证”),这时服务器会给用户的手机发送一条短信

  2. 用户查收短信后,输入短信验证码,点“注册”,服务器进行验证,如果正确,执行注册逻辑

     

常规的服务器端处理流程

  1. 第一步,服务器生成一个四位随机码作为短信验证码,发短信出去,同时在数据库或redis里,记录下该手机号对应的这个验证码以及超时时间

  2. 第二步,用户输入验证码点“注册”后,服务器端在数据库或redis里取到上步记录的验证码,进行对比,如果相同,认证成功,继续后续业务处理

大家可以看到,常规的服务器端处理,是需要操作数据库或redis的,如果数据库或redis挂掉,用户注册这个关键业务就没法进行了。 即使不挂掉,它们也可能成为性能瓶颈

滴滴在《高可用架构》会场上分享了他们的实现方案:把方案做成无状态的,即,不依赖数据库或redis。 这是个很棒的思路,无状态带来的最好处多多(比如方便扩容、、)

在会议现场提问环节,我提出了改进意见,由于时间仓促,没有与主持人深入交流,会后也因为私事匆匆离开,也没机会进一步交流

下面是我的改进方案,不涉及短信防刷这类“无关”问题(因为无论哪种方案,都需要处理防刷)。 本质原理与滴滴的方案相同,全都是在非对称摘要算法上做文章

第一步:用户输入手机号,点击“获取验证码”

这时,http request包含了用户填写的手机号:

phone= 18612345678

 


服务器端,生成一个随机的四位码作为短信验证码(verify_code),发短信出去(这步略),为了方便,我用ruby代码表达,下同

verify_code = " #{rand( 10 )} #{rand( 10 )} #{rand( 10 )} #{rand( 10 )} "

 


算出过期时间exp(验证码5分钟后过期):

exp = Time.now + 5.minutes

 


假设服务器端有一个全局的SECRET(注意别泄漏):

SECRET = "THIS_IS_A_SECRET"

 


我们把这几项拼成一个大的string,算一个摘要值(token)出来:

require ( 'digest' ) token = Digest::SHA256 .hexdigest(phone + verify_code + exp + SECRET )


摘要算法我这里选了SHA256,可以根据情况调整


在本次请求的http response中,把exp和token传回客户端,类似:

{  " exp ": "2016-07-03 00:32:19 +0800" ,  " token ":"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
}

第二步:用户输入短信验证码,点“登录”

这时,用户提交的http request中包含如下信息(在服务器端,我们用四个变量表示它们 ):

phone= 18612345678
verify_code_input= 用户填的短信验证码
token= 上步传回的值
exp= 上步传回的值

 

服务器端先检查一下短信验证码是不是超过5分钟有效期了:

if Time .parse(exp) < Time .now  halt( "短信验证码已失效,请重新获取" )
end

 

再检查用户输入的短信验证码是不是正确,算法跟上步一样:

require ( 'digest' ) token2 = Digest::SHA256 .hexdigest(phone + verify_code_input + exp + SECRET )
   
if token2 != token  halt( "短信验证码不正确,请重新获取" )
end

# 下面是验证通过后的代码了...

 

这样整个验证过程就完成了

 

附个流程图:

论短信验证码在 服务器 端的最佳处理姿势

后记:可行性和安全性

攻击者因为手里没有SECRET,所以无法伪造token。 这一点保证了整个方案的可行性

同样因为有SECRET,所以攻击者用rainbow table破解就不可行了,而且有exp定义超时时间,安全性有进一步提升。 实在不小心,SECRET泄漏了,攻击者可以实施的威胁就大的多了,不过这也是其它依赖SECRET的方案的一个通用问题(比如滴滴目前的方案)

 

服务器端换SECRET,造成的影响不过是最近几分钟内用户获取的短信验证码无效,需要用户再获取一次而已,可以接受

转载于:https://www.cnblogs.com/qq1069284034/p/8867419.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值