短信验证码系统怎么设计?一次讲清发送频控、验证码校验、防刷与通道容灾
短信验证码系统怎么设计?一次讲清发送频控、验证码校验、防刷与通道容灾
大家好,我是一名有 4 年工作经验的 Java 后端开发。
短信验证码功能看起来简单,但真正做成稳定系统,里面其实有很多风控、频控、通道和可用性问题。
这篇文章我想系统聊一聊短信验证码系统到底该怎么设计。
🦅个人主页
🐼
文章目录
- 短信验证码系统怎么设计?一次讲清发送频控、验证码校验、防刷与通道容灾
- 一、验证码系统最容易被低估的地方
- 二、推荐的核心流程
- 三、频控一定要做在哪几层
- 3.1 单手机号频控
- 3.2 单 IP 频控
- 3.3 单设备频控
- 3.4 单日总量限制
- 四、验证码校验要注意什么
- 4.1 TTL
- 4.2 一次性使用
- 4.3 错误次数限制
- 五、通道容灾怎么做
- 六、最容易踩的坑
- 6.1 只做手机号限流,不做 IP / 设备限制
- 6.2 验证成功后不删除验证码
- 6.3 短信发送失败也把验证码写成功
- 6.4 没有发送日志
- 七、面试中怎么回答
- 八、总结
- 九、结尾
一、验证码系统最容易被低估的地方
很多人第一次做验证码,代码通常是:
- 生成 6 位数
- 存 Redis
- 调短信接口发送
这当然能跑,但很快就会遇到:
- 同一个手机号疯狂发验证码
- 图形验证码都没做就被打爆
- 短信通道偶发失败
- 用户明明输对了却提示错误
- 验证码被重复使用
所以验证码系统真正要解决的是:
生成、发送、校验、防刷、通道可用性和风控一起设计。
二、推荐的核心流程
- 先做人机验证或基础风控
- 生成验证码
- 验证码写入 Redis,并设置 TTL
- 走短信通道发送
- 校验时从 Redis 比对
- 验证成功后立即失效
这个流程里最关键的是:
- 频控
- 一次性
- 发送成功留痕
三、频控一定要做在哪几层
我更建议至少做这些限制:
3.1 单手机号频控
例如:
- 60 秒内只能发一次
3.2 单 IP 频控
防止恶意机器刷接口。
3.3 单设备频控
更进一步防刷。
3.4 单日总量限制
避免通道成本和攻击风险。
四、验证码校验要注意什么
4.1 TTL
通常验证码有效期不要太长,比如:
- 5 分钟
4.2 一次性使用
校验成功后应立即删除。
4.3 错误次数限制
比如:
- 连续输错 5 次锁定一段时间
五、通道容灾怎么做
短信通道并不总是稳定的。
所以如果短信量大,建议:
- 主通道
- 备通道
- 失败切换
同时要有:
- 发送结果日志
- 通道成功率监控
六、最容易踩的坑
6.1 只做手机号限流,不做 IP / 设备限制
很容易被批量刷。
6.2 验证成功后不删除验证码
这会让验证码变成可重复使用。
6.3 短信发送失败也把验证码写成功
后面会出现用户拿不到码,但系统以为已经发成功。
6.4 没有发送日志
排查投诉会很困难。
七、面试中怎么回答
如果面试官问你:
短信验证码系统一般怎么设计?
你可以这样回答:
第一,我会把验证码系统拆成生成、发送、校验和风控四层,不会只把它当成一个简单的 Redis + 短信接口调用。
第二,风控和频控非常关键,至少会限制单手机号、单 IP、单设备的发送频率,并对单日发送量做控制,避免被恶意刷接口。
第三,验证码在 Redis 里通常会设置较短 TTL,校验成功后立即删除,保证一次性使用;同时短信通道侧最好有发送日志和通道容灾能力,方便排查和切换。
八、总结
验证码系统真正难的,不是生成 6 位数,而是如何把:
- 发送
- 校验
- 频控
- 风控
- 通道稳定性
真正一起考虑进去。
如果只记一句结论,我觉得可以记住这句:
验证码系统最稳的做法不是只把验证码存进 Redis,而是“频控、一次性、发送留痕、通道容灾”一起设计。
九、结尾
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注。
后面我会继续整理一些更偏实战的 Java 后端和基础设施设计文章,尽量少写空泛概念,多写真实项目里会踩到的坑。
