基于API与PHP的短信OTP验证:如何安全校验验证码?
OTP验证方案建议
核心思路:避免存储手机号,用临时令牌关联OTP
不用直接存手机号,而是在发送OTP前生成一个唯一临时令牌,把令牌和OTP绑定存储,同时将令牌通过安全方式发给前端。验证时前端提交令牌+输入的OTP,后端匹配校验即可。
具体实现方案
方案1:数据库临时表存储(适合无缓存服务的场景)
- 创建独立的
otp_verifications表,不需要手机号字段,只需包含:token_hash: 唯一随机字符串(比如32位UUID)的哈希值(用SHA-256加密,避免明文泄露)otp_hash: 6位OTP的哈希值(用bcrypt加盐存储,防止暴力破解)expires_at: 过期时间(比如设为5分钟后,避免OTP长期有效)is_used: 布尔值,标记是否已使用,防止重复验证
- 流程:
- 用户提交手机号,后端生成6位OTP和32位UUID令牌
- 将令牌哈希、OTP哈希、过期时间存入表中
- 把原始令牌存入HttpOnly、Secure属性的Cookie(前端无法读取,避免泄露风险)
- 调用短信API给用户发送OTP
- 用户输入OTP提交后,后端从Cookie中获取令牌,哈希后去表中查找对应记录
- 校验OTP哈希是否匹配、是否过期、是否未使用,通过则标记记录为已使用,验证成功
方案2:Redis缓存存储(更适合临时数据,性能更高)
- 用Redis键值对存储,不用建表:
- 键:格式为
otp:token:{UUID},其中UUID是生成的唯一令牌 - 值:JSON格式,包含
otp_hash和expire_at - 直接给Redis键设置过期时间(比如5分钟),到期自动清理,无需手动维护
- 键:格式为
- 流程和方案1一致,只是把存储介质换成Redis,验证时直接根据令牌键查找值,校验逻辑相同
关于触发器/存储过程的说明
触发器和存储过程在这里完全没必要用,它们主要用于数据库层面的自动化操作(比如数据变更时触发动作),而OTP验证是业务逻辑层面的处理,用普通业务代码实现更灵活、易维护。
内容的提问来源于stack exchange,提问作者Mahmut Salman
相关产品推荐
相关产品推荐

