Rails结合Devise手动发送确认邮件的自定义6位OTP方案是否安全?
安全风险说明
你的实现存在多处明显的安全隐患,具体如下:
skip_confirmation!调用逻辑错误:该方法会直接将用户的confirmed_at字段标记为当前时间,等价于直接完成账户确认流程,你后续发送确认邮件的操作完全失效,即使用户不做任何确认操作,账号也已经处于已确认状态。- 6位数字OTP熵值不足:6位数字总共仅存在100万种组合,暴力破解成本极低,攻击者可以用自动化工具针对目标账号批量尝试所有可能的组合,短时间内就能完成撞库。
- 随机数生成方法不安全:你使用的
rand(10)是普通伪随机数生成器,不具备密码学安全强度,生成的序列存在被预测的可能,进一步降低了攻击门槛。 - 缺少有效期和错误次数限制:当前代码仅记录了token发送时间,没有设置OTP的有效时长,也没有限制验证的错误次数,攻击者拿到历史OTP或者多次尝试都能完成验证,放大了泄露和破解风险。
优化方案
- 直接删除
user.skip_confirmation!调用,保持devise默认的未确认状态拦截逻辑,仅当用户提交正确OTP后再调用user.confirm!完成确认。 - 给OTP增加15分钟有效期,验证时先判断
confirmation_sent_at是否在有效期内,过期直接作废。 - 新增频率和错误次数限制:同一个账号1分钟内最多申请1次OTP,单日累计申请超过5次锁定1小时;OTP验证连续错误3次直接作废,需重新申请,避免暴力破解。
- 替换随机数生成逻辑,使用密码学安全的随机数方法:将
rand(10)替换为SecureRandom.random_number(10),避免随机序列被预测。 - 业务允许的前提下,可以将OTP长度调整为8位,将暴力破解的组合量级提升到1亿次,大幅提高攻击成本。
内容的提问来源于stack exchange,提问作者JIGME
相关产品推荐
相关产品推荐

