记一次短信验证码服务异常排查:从通道稳定性想到的多因素认证设计

页面二

去年秋天,我在做一个面向海外用户的SaaS项目,注册流程需要短信验证码做身份校验。+86手机号作为测试账号,验证码要么延迟十分钟以上,要么干脆收不到。

这个问题在开发和测试环境没出现过,到了预发布环境才暴露。排查了三天,最后发现不是代码bug,是通道本身的稳定性问题。

第一天:排除代码层面的问题

项目用的是.NET 6,短信服务封装了一个HttpClient调用第三方API。本地调试时,+1(美国)和+44(英国)的号码都能正常收到验证码,平均延迟3秒。

但换成+86号码后,现象很奇怪:

请求返回200,状态显示"已发送"

实际手机收不到短信

偶尔能收到,但延迟超过10分钟,验证码已过期

我第一反应是HttpClient配置有问题。检查了超时设置、DNS解析、TLS版本,都没异常。又怀疑是第三方SDK的bug,降级了版本,问题依旧。

第一天结束时,基本排除了代码和SDK的问题。

第二天:对比不同运营商和通道

第二天做了更系统的测试:

电信卡:发送10次,收到2次,平均延迟15分钟

联通卡:发送10次,收到5次,平均延迟8分钟

移动卡:发送10次,收到1次,延迟超过30分钟

同时发现,同一个号码重复发送时,第二次会提示需要支付额外费用(smsfee),但支付后依然收不到。

这时候我意识到,问题不在我们的系统,在短信通道本身。+86号码走的是国际短信通道,近期这条通道的稳定性明显下降。不是技术问题,是基础设施层面的限制。

第三天:思考替代方案和架构改进

既然短信通道不可靠,有没有其他验证方式?

我调研了几种替代方案:

方案一:邮件验证

实现简单,SMTP现成的

但国内用户邮箱使用率不高,且邮件进垃圾箱的概率大

作为辅助可以,不能替代

方案二:第三方OAuth授权

微信、GitHub、Google等

但我们的用户群体分散,不是所有用户都有这些账号

且OAuth引入额外的依赖和隐私合规问题

方案三:基于时间同步的软令牌(TOTP)

类似Google Authenticator的实现

不依赖任何通道,完全离线

但用户教育成本高,且需要额外安装App

最终采用的架构

没有选单一方案,而是做了分层设计:

主通道:短信验证码,覆盖大部分用户

备用通道:邮件验证,短信失败时自动切换

兜底方案:TOTP软令牌,对安全要求高的用户可选

通道健康检查:每5分钟检测各通道成功率,低于阈值自动告警并切换

代码层面,用Polly做了重试和熔断:

短信发送失败,重试2次

连续5次失败,熔断该通道10分钟,切换到备用

熔断期间,新请求直接走备用通道

这次排查的收获

以前做系统架构,我默认"短信通道是可靠的",把短信作为唯一验证方式。这次经历让我意识到,任何外部依赖都可能失效,设计时要考虑降级和兜底。

特别是面向全球用户的产品,不同地区的网络环境、运营商策略、政策法规差异很大。不能用一个假设覆盖所有场景。

几个设计原则:

多通道并行:不要依赖单一验证方式

自动降级:主通道失败时,用户无感知切换

健康监控:实时知道哪个通道有问题,而不是等用户投诉

失败透明:告诉用户"当前通道繁忙,已切换备用方式",而不是"请稍后再试"

最后的问题

你们在做多因素认证或注册流程时,有没有遇到过"某个验证通道在特定地区完全不可用"的情况?最后是怎么处理的?是硬等通道恢复,还是做了备用方案?

我目前的设计是Polly做熔断切换,但TOTP的用户教育成本还没找到好的解决办法。有经验的朋友欢迎分享。

我分享在评论区了

posted @ 2026-06-13 17:12  freedangke  阅读(1)  评论(1)    收藏  举报