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


    转载: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,造成的影响不过是最近几分钟内用户获取的短信验证码无效,需要用户再获取一次而已,可以接受

  • 相关阅读:
    kickstart自动安装部署RHEL7
    物流即使查询API
    快递单号查询快递鸟API接口-100家快递单轨迹推送
    物流跟踪API-快递单订阅
    如何最快实现物流即使查询功能-物流轨迹查询API
    提供一个不错的物流物流接口给大家,本人亲测,真的不错
    给idea添加类注释和方法注释模板
    分享一个生成反遗忘复习计划的java程序
    用TreeSet和Comparator给list集合元素去重
    对poi-excel导出的浅层理解
  • 原文地址:https://www.cnblogs.com/qq1069284034/p/8867419.html
Copyright © 2020-2023  润新知