Java Spring Boot项目如何合理处理暴力登录尝试问题
问题1:登录失败计数封禁方案合理性及优化建议
你规划的基础方案逻辑是通顺的,完全可以落地,且天然支持管理员手动解封的需求,但存在部分可优化的空间和潜在风险:
- 基础方案的优缺点:
- 优势:实现门槛极低,数据持久化存储不会因为服务重启、缓存击穿丢失封禁记录,管理员直接操作数据库用户表的状态字段就能完成手动解封,符合你的功能要求
- 缺陷:每次登录失败都读写数据库,高并发场景下会加重数据库压力;如果攻击者批量遍历不存在的用户名发起攻击,会产生大量无用的计数垃圾数据;如果用定时任务扫表实现自动解封,会存在最大一个扫表间隔的时间误差,且频繁扫表也会额外消耗数据库性能
- 优化后的落地方案:
推荐用「缓存+数据库」的双层架构实现,同时兼容自动+手动两种解封模式:- 前8次登录失败的计数直接存在Redis中,设置30分钟过期时间,不需要读写数据库,大幅降低DB压力;针对不存在的用户名,计数全部存在Redis,不落库,避免垃圾数据
- 失败次数累计到9次时,将计数同步写入数据库的用户表,同时在Redis中写入该用户的封禁标记,标记同样设置30分钟过期,到期自动删除即可实现自动解封
- 管理员手动解封时,同时删除Redis中的封禁标记、重置数据库中的失败次数和封禁状态即可,操作逻辑非常简单
- 如果没有引入Redis,也可以在用户表新增
ban_expire_time字段,每次查询用户登录状态时判断当前时间是否超过过期时间,自动执行解封逻辑,不需要单独跑定时任务扫表
问题2:技术选型及Spring Security适配性说明
Spring Security完全适配你的需求,是当前场景的首选技术方案,不需要额外引入无关组件:
- 基于Spring Security的实现逻辑:
- 自定义
AuthenticationFailureHandler,在登录失败回调中执行失败计数累加、阈值判断、封禁标记写入的逻辑 - 自定义
AuthenticationSuccessHandler,登录验证通过后清空缓存和数据库中的失败计数 - 自定义
UserDetailsChecker,在登录验证流程的前置步骤先检查用户是否处于封禁状态,如果已封禁直接抛出异常终止验证,不需要走完后续的密码校验流程
- 自定义
- 额外可补充的防护逻辑:
- 新增IP维度的封禁规则,同一个IP短时间内出现超过阈值的登录失败请求(无论用户名是否存在),直接封禁该IP一段时间,从源头拦截批量撞库攻击
- 当用户登录失败次数达到5次时,强制要求输入reCaptcha验证码后才能继续尝试登录,进一步提高攻击成本
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

