不就是个短信登录API嘛,有这么复杂吗?

引子
上联:这个需求很简单
下联:怎么实现我不管
横批:今晚上线

Part 1:暴力破解

早上开完站会,小李领了张新卡,要对登录功能做升级改造,在原来只支持用户名密码登录模式的基础上,新增手机号和短信验证码登录。

业务分析师薇薇早就准备好了故事卡,并且也考虑到这个功能的特殊性,除了平常的业务性验收标准外,还专门添加了一些和安全有关的条目。这张故事卡看上去是这样的:

故事卡-274
作为用户,我可以通过手机号和短信验证码登录,以便于我更方便的登录。
安全验收标准:

  • 短信验证码有效期5分钟
  • 验证码为4位纯数字
  • 每个手机号60秒内只能发送一次短信验证码

小李看到故事卡中提到,验证码长度只有4位而且还是纯数字,隐约觉得强度有些不够,担心万一黑客来个多线程并发请求,或者拿一个集群来暴力登录,有可能会赶在有效期内破解出合法的验证码。

小李把自己的担心讲给了业务分析师薇薇,并且建议把验证码长度增加到6位,或者在保持4位长度的情况下,改为数字和字母的组合,目的是增加验证码复杂性,提高暴力破解的门槛。

薇薇听了这两种选择后直摇头,说道:“我理解你的担心,可是业务部门那边的需求很明确,就是为了优化用户登录体验,所以才决定做手机号和验证码登录,如果把验证码弄的这么复杂,那用户体验也好不到哪里去,不符合这个故事卡的初衷啊。”

“对于用户而言,4位数字验证码确实好记好填,可是对于黑客而言,就能很容易的完成暴力枚举,理论上最多1万次请求就能遍历完所有的验证码,更何况黑客没那么倒霉,要尝试到第1万次才猜对……”,小李说道。

为了满足用户体验而在安全性上做出妥协,这种事情小李觉得自己无法说服自己,正准备掏出纸和笔跟薇薇做详细解释黑客攻击手段的时候,团队技术负责人老罗听见了他们两的讨论,慢慢脱下帽子,摸了摸正在朝着“地中海”模式演进的乌黑的秀发,说道:“那啥,服务器在验证登录请求的时候,不管验证码匹配还是不匹配,存在Redis里的验证码只要被取出来就立即作废,根本不给黑客暴力破解的机会。”

小李的团队已经搭建好了Redis,用来存储登录过程中发给用户的短信验证码,是一个手机号和验证码的键值对。

“对啊”,小李感觉眼前一亮,说道,“服务器在比对请求中的验证码和Redis中保存的这个用户手机号所对应的验证码的时候,如果发现不匹配,那依然还是直接把Redis中的这个验证码作废。这样黑客发第二次登录请求的时候,会因为Redis中找不到对应的记录而登录失败。这样既避免了暴力枚举攻击,同时也不再需要增加验证码的强度,导致用户体验的下降了。”

小李建议把刚才的讨论结果写到故事卡里,而薇薇提议能否不要立即作废:“万一用户输入验证码的时候手滑输错了,岂不是要等几十秒的时间再重新发第二个验证码?”

“可以做到验证码3次输入错误后就作废吗?”薇薇问到。

“可以的,这个不难”小李坚定的回答到。

“好,那我们加一条安全验收标准吧”,薇薇边说边修改了故事卡,新增加了一条:

保存于服务器端的验证码,至多可被使用3次(无论和请求中的验证码是否匹配),随后立即作废,以防止暴力攻击

“对了小李”,老罗喝了口咖啡,最近连续的加班让老罗感觉很疲惫,只能靠喝咖啡强打精神。“60秒内只能发1次短信那条,别忘了前后端都要做检查。”

“知道知道,前端做不做都无所谓,关键是在后端要做限制。”小李连连点头。

“好,那就这么做,去忙吧”。老罗转身坐下,正准备继续刚才被打断的工作,此时一个念头快速在脑海里一闪而过,老罗在电脑上打开短信登录的这张故事卡,从头到尾又看了一次,最后目光停留在“短信验证码有效期5分钟”这条验收标准那里。

“短信每60秒发一次”,老罗心想:“但有效期是5分钟,那第61秒的时候假如又请求发送一次验证码,这时第一次发送的验证码还没过期,服务器端该怎么处理这个请求会比较稳妥呢?

显然,第二个验证码直接覆盖掉第一个会更加安全,也就是至始至终都只有一个处于有效状态的验证码,但这会不会给用户带来困惑?毕竟偶尔还是有手机信号不好,等了1分钟多钟之后才收到第一个验证码的情况。

如果不替换而是追加验证码呢?最极端的情况是会出现一个手机号有5个有效验证码的情况,会增加黑客暴力破解的成功概率。不过因为一个验证码最多只能被使用3次,之后就被作废了,所以实际上黑客暴力破解的难度依然很高。

总的来说,直接覆盖的做法用户体验不佳但更安全,依然有效的做法用户体验更好但相对而言安全性略有降低。”

经过反复思考后,老罗最终选择保留验证码5分钟有效期的设置。

Part 2:防不胜防

短信验证码登录的功能上线后,运行状态一直比较平稳,然而这种平静的氛围被一通电话打破了。

“喂,对,是我”,老罗桌上的电话响了,他忙着写代码,歪着脖子用肩膀和脸夹住话筒说道:“是客服部啊,有什么事我可以帮忙的?”

“是这样,我们今天突然收到很多顾客打来的电话,抱怨说收不到短信验证码,登录不了账户,他们基本都是新用户,只有用手机注册的账号,没有用户名密码,所以也不能用原先的用户名密码去登录账号。我们只好让顾客再等会儿试试,可能是信号不好,但后来他们反馈说还是收不到我们的短信,而且只是收不到我们的短信,所以,你们那边能帮忙看看是怎么回事吗?”电话那边一口气讲了一堆话。

“还有这种事,行,我知道了,我们马上调查分析一下。”老罗刚挂断电话,运维部的同事过来找到老罗,说短信配额今天消耗得很厉害,已经触发了2次告警了,运维同事做了一下简单的分析,发现早上10点和下午2点左右有两批次大量发送登录短信验证码的请求,但又没有观察到对应的后续登录请求,判断可能是被黑客攻击了,于是临时性的屏蔽了攻击来源IP地址的访问。

“来找你就是想和开发团队共同调查下这个问题,看接下来怎么处理会比较好。”运维部的同事说道。

老罗觉得这个事和刚刚接到的客服部门说的是同一件事,便把刚才电话里听到的信息和运维同事讲了一遍。

“这更能证实是黑客攻击了,而且看来他们的目标应该不是暴力登录,而是故意消耗短信发送配额,一旦配额被用完,用户就无法正常登录,也算是某种程度上的拒绝式服务攻击了。” 运维部的同事说完看向老罗。

老罗若有所思的说道:“没想到他们还能这么玩儿。我们目前只限制了一个手机号60秒内发一次验证码,却没有应对大量不同手机号的情况。”

“那现在怎么处理比较好呢?虽然临时禁用了攻击者的IP,但我们担心会误伤真实用户,而且黑客也可能会变换IP来继续进行攻击。”运维同事继续问道。

“有办法,在发短信验证码之前先要求输入图形验证码。”

“嗯,有道理,你们什么时候能做好上线?”

“我现在就加”,老罗还没说完就已经开始写代码了:“一会儿弄完紧急上线。”

“行,我回去安排一下,咱们运维部全力配合。”

“看来之前那张故事卡里的安全验收标准还差了一条”,老罗自然自语道:“如果加上一条图形验证码的要求恐怕就不会出这个事儿了。”

发送短信验证码之前,先验证图形验证码是否正确

Part 3:权衡

“喂喂喂,这搞的什么鬼?”用户体验设计师Jenny抓住路过的老罗说:“我不过就是休了两天假,回来之后怎么发现登录这里多了个图形验证码出来?”

老罗向Jenny解释了这个图形验证码的由来,是出于安全的考虑才增加的。

“我知道安全很重要,可是这图形验证码太伤害用户体验了,现在顾客登录过程中就要再多做一次输入,如果填错了还得重新再来一次,而且这图形验证码的风格和我们的App风格明显不匹配,另外,这图形验证码是不是也太扭曲了,我都看错好几回了……。”Jenny显然并不认同这个方案。

“风格我们可以修改,这不是还有你嘛。”老罗为难的说到:“难度高是因为现在的图像识别技术突飞猛进,简单图片验证码很容易被破解。”

“莫非就没有别的解决办法了吗?”Jenny继续问道。

“其实也有,就看公司舍不舍得花这笔钱了。”老罗接着说:“登录界面可以动态决定是否要求输入图形验证码,对于正常用户可以让他们无需输入图形验证码,对于黑客或者疑似黑客的人,就要求他们输入。”

“这听上去很好啊,另外,这和舍不舍得花钱有什么关系?”Jenny不太明白。

“要动态决定是否要求输入图形验证码这件事儿,其实就是判断当前用我们App的人是真实的顾客还是黑客。我们自己没这个判断能力,不过有提供这种服务的第三方API,只是他们都不是免费的,得花钱买。”老罗向Jenny解释到。

阿某云和腾某云等等都提供这类服务,其主要原理是,服务器在处理登录请求的时候,先尽可能多的收集该请求的上下文信息,例如登录请求的来源IP地址,时间,手机号,User-Agent等等数据,并且把这些数据传递给第三方API,由他们进行一次分析判断,并把结果返回给服务器,告诉服务器当前请求者是可信用户还是可疑用户。最终是否允许登录成功的决定权还是在服务器这边,只是借助了第三方API提供的分析结果来做判断而已。

“我不懂技术,不过好像也听懂了的样子。"Jenny笑着说道。

“用第三方API做登录判断这事儿我拍不了板,得找领导批准,说不定还得走采购流程。”但老罗觉得这条路的方向是对的。

“走,我们去问问领导的意见,我实在受不了现在这个图形验证码。”Jenny拉着老罗径直朝着总经理办公室走去。

尾声

最终,老罗他们团队用上了某云的第三方API做登录防护,去掉了令Jenny抓狂的图形验证码。经过和业务部门的商量,验证码有效期最后缩短到了2分钟。

在这期间还出现了两个小插曲。运维部门的同事偶然间发现,应用程序日志文件里居然保存了所有用户的短信验证码,这是小李当初做调试的时候加上去的,后来忘记关掉了。好在并没有造成泄露,后来团队修复了这个问题。

另一个小插曲是,团队做了微服务架构改造,把发送短信的功能拆分出来做成了一个独立微服务,但却没有给这个新的接口设置好访问控制权限,以至于任何人在无需登录的情况下,只要向这个接口发起请求就能成功发送一条短信给任意手机,短信内容还可以自定义。这个问题在安全团队做渗透测试的时候发现的,吓得老罗浑身冒冷汗。所幸发现及时,做了紧急修复,并没有造成安全事故。

薇薇后来把短信登录的故事卡作为案例保存了起来,把安全验收标准又重新做了一次梳理,所以最终的故事卡是这样的:

故事卡-274
作为用户,我可以通过手机号和短信验证码登录,以便于我更方便的登录。
安全验收标准:

  • 短信验证码有效期2分钟
  • 验证码为6位纯数字
  • 每个手机号60秒内只能发送一次短信验证码,且这一规则的校验必须在服务器端执行
  • 同一个手机号在同一时间内可以有多个有效的短信验证码
  • 保存于服务器端的验证码,至多可被使用3次(无论和请求中的验证码是否匹配),随后立即作废,以防止暴力攻击
  • 短信验证码不可直接记录到日志文件
  • 发送短信验证码之前,先验证图形验证码是否正确(可选)
  • 集成第三方API做登录保护(可选)

没成想,一个短信登录API背后,还能牵扯出这么多事儿来。


文/ThoughtWorks马伟

更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,639评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,277评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,221评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,474评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,570评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,816评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,957评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,718评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,176评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,511评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,646评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,322评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,934评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,755评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,987评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,358评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,514评论 2 348

推荐阅读更多精彩内容