随着手机的普及,手机验证码登录需求已经成为一个很常见的需求,但是这么一个看似简单的需求,其实还是有很多坑的。
昨天使用兄弟团队的登录界面,就发现了一些安全问题,在这边整理了一些我的经验和坑点,写下来备忘和参考。
这点只要做过一段时间Web开发的,都理解:
我见过的反面案例:
用户输入的手机号是不是合法的格式,鉴于现在手机号段,都是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
如果不做频率控制,那么恶意用户可能无限发送短信,把你的接口作为短信轰炸机,轰炸别人,造成你的成本浪费,甚至可能被工信部调查。
常见作法(注:以下步骤,建议全部实现):
可能导致的问题点:
我见过的反面案例:
基于用户体验,现在生成的手机验证码,90%以上都是随机的全数字,有4位,有6位。
基于安全考虑,建议使用随机生成的6位数字,同时应当避免生成极简单的验证码,减少碰撞概率。
注:应当使用一个静态的Random变量,运行过程中new的变量可能生成相同的验证码。
应当避免生成的验证码规则:
我见过的反面案例:
注:复杂验证码也有碰撞概率,但是相对简单数字,概率比较小
为了避免暴力破解,对验证码应该有验证次数、验证时效的限制:
我见过的反面案例:
6.1、验证码必须跟手机关联,即:服务端要根据手机号,查找最近一条验证码,避免其它手机号的验证码被使用;
6.2、存在多项目时,验证码必须跟项目或顺序关联:
为避免多项目间的验证码串扰,或同一项目发了多次验证码时,使用哪一个验证码有效的问题,生成的验证码应该配对一个序列号,用户输入验证码,点登录时,把序列号一起带给服务端进行校验。
加上了上面的限制,依然不可避免被利用,比如市面上的短信轰炸机,就是收集了网上几乎所有的短信验证接口,它只需要每个接口调用一次就够了,什么新浪网易淘宝,都被短信轰炸机收录了。
这种恶意应用,几乎无法避免,只能不断修改发送规则,举几个例子:
