• 短信验证码登录需求的坑点整理


    随着手机的普及,手机验证码登录需求已经成为一个很常见的需求,但是这么一个看似简单的需求,其实还是有很多坑的。
    昨天使用兄弟团队的登录界面,就发现了一些安全问题,在这边整理了一些我的经验和坑点,写下来备忘和参考。

    1、所有的数据存储和验证,一定要在服务端处理。

    这点只要做过一段时间Web开发的,都理解:

    • 前端的数据、加密算法、密钥都是公开的,很容易泄露。
    • 前端的验证,都是可以绕过的,只能作为用户体验优化方案,服务端都必须做验证。

    我见过的反面案例:

    • 后端生成验证码,明文或经过加密后返回给前端,前端在js里判断输入的验证码是否正确

    2、手机号格式校验

    用户输入的手机号是不是合法的格式,鉴于现在手机号段,都是1开头,第2位除了0,1和2,其它都有,我常用的正则是: ^1[3-9]\d{9}$
    注1:网上找到了号段分布:
    一、中国电信号段133、149、153、173、177、180、181、189、190、191、193、199
    二、中国联通号段130、131、132、145、155、156、166、167、171、175、176、185、186、196
    三、中国移动号段134(0-8)、135、136、137、138、139、1440、147、148、150、151、152、157、158、159、172、178、182、183、184、187、188、195、197、198
    注2:服务端一定要校验手机号格式是否合法,但是前端也建议加上,增强用户体验。

    我的案例,号段变化太快,导致校验规则代码不断调整:
    以前只有13x号段,后面增加15x、18x,再后面又增加17x、19x,又增加14x、16x。
    具体号段发展历史参考:https://www.cesc.com.cn/quote/show-358652.html

    3、短信发送频率控制

    如果不做频率控制,那么恶意用户可能无限发送短信,把你的接口作为短信轰炸机,轰炸别人,造成你的成本浪费,甚至可能被工信部调查。
    常见作法(注:以下步骤,建议全部实现):

    • 根据用户IP,限制发送次数,比如 一个IP一分钟内只能发一次短信
    • 根据用户手机号,限制发送次数,比如 同一个手机号一分钟内只能发一次短信
    • 同一个IP 或 同一个手机号,一天内发送超过3条短信时,增加图形验证码或滑块等机制
    • 同一个手机号,一天内发送超过20条短信时,加入黑名单,禁止调用
    • 同一个IP,一天内发送超过100条短信时,加入黑名单,禁止调用

    可能导致的问题点:

    • 一个公司或一个区域的用户,可能是同一个出口IP,导致有些人互相影响
    • 在不同产品之间同时登录,是否允许同时发短信,此时Redis的key可以加上产品标识

    我见过的反面案例:

    • 之前百度某项目,修改个人资料需要短信验证,没做频率控制,造成一天发了400万条短信
    • 前一公司登录页,使用Session或Cookie,进行发短信的频率控制,在代码评审时发现。
      我戏称:这段代码只限制了公司的前端团队,没有限制恶意用户。

    4、验证码生成规则

    基于用户体验,现在生成的手机验证码,90%以上都是随机的全数字,有4位,有6位。
    基于安全考虑,建议使用随机生成的6位数字,同时应当避免生成极简单的验证码,减少碰撞概率。
    注:应当使用一个静态的Random变量,运行过程中new的变量可能生成相同的验证码。

    应当避免生成的验证码规则:

    • 相同的数字,如 000000 111111
    • 连续的数字,如 123456 67890

    我见过的反面案例:

    • 曾经收到过 222222 这种验证码,如果恶意用户输入了222222,就进去了

    注:复杂验证码也有碰撞概率,但是相对简单数字,概率比较小

    5、验证码失效规则

    为了避免暴力破解,对验证码应该有验证次数、验证时效的限制:

    • 登录成功后,该验证码应当立即失效,不允许再次使用
    • 验证码校验错误5次,该验证码应当立即失效,不允许再次使用
      注:1次也可以,会多点钱,用户体验也差一点
    • 验证码在180秒内有效,超时后该验证码应当立即失效,不允许使用
    • 发送验证码成功时,所有的验证码应当全部失效,不允许使用
      注:最简单作法,根据手机号,查找最后一条验证码(不管状态,最后一条是失效的也要获取)

    我见过的反面案例:

    • 上文写的兄弟团队的登录页面,就没有对错误次数做限制,6位数字,最坏情况下999999次登录,一定可以登录成功。
    • 验证码成功后不失效,导致退出后,还可以使用上一次成功的验证码

    6、验证码关联规则

    6.1、验证码必须跟手机关联,即:服务端要根据手机号,查找最近一条验证码,避免其它手机号的验证码被使用;
    6.2、存在多项目时,验证码必须跟项目或顺序关联:
    为避免多项目间的验证码串扰,或同一项目发了多次验证码时,使用哪一个验证码有效的问题,生成的验证码应该配对一个序列号,用户输入验证码,点登录时,把序列号一起带给服务端进行校验。

    7、其它

    加上了上面的限制,依然不可避免被利用,比如市面上的短信轰炸机,就是收集了网上几乎所有的短信验证接口,它只需要每个接口调用一次就够了,什么新浪网易淘宝,都被短信轰炸机收录了。
    这种恶意应用,几乎无法避免,只能不断修改发送规则,举几个例子:

    • 进入登录页,服务端生成一个token给前端,前端发短信必须带上这个token,没有token或token无效不让发短信
    • 进入登录页,调用一个接口,起个奇怪的名字,比如 addlog,其实是在服务端生成一个Session,发短信时,服务端不存在Session,报一个服务器失败,不给用户明确的提示
    • 对上面这些非法请求的IP,加入黑名单

    8、短信登录流程图

    在这里插入图片描述

  • 相关阅读:
    体验中国移动云:探索移动云服务的独特魅力
    不同访问修饰符的访问数据权限的区别
    制作一个简单HTML游戏网页(HTML+CSS)仿龙之谷网络游戏官网
    Rust基础入门之变量绑定与解构
    【面试高频题】难度 1.5/5,LCS 模板题
    GaiaX开源解读 | 跨端动态化模板引擎详解,看完你也能写一个
    python:神经网络的卷积核,权重矩阵长什么样子?
    阿里云服务器和腾讯云服务器哪个更好?多维度对比得出了结论
    30K Star,最全面的PDF处理开源项目,你也可以拥有一个本地的PDF处理大全
    【RPC 协议】序列化与反序列化 | lua-cjson | lua-protobuf
  • 原文地址:https://blog.csdn.net/youbl/article/details/127124527