You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需数据库与Session存储完成OTP校验

无存储OTP校验实现方案

核心逻辑是把OTP和校验所需的元数据加密后直接下发给客户端,服务端全程不留存任何OTP相关数据,校验时通过解密验签完成合法性判断,完全不需要依赖数据库、Session等存储介质。

生成OTP阶段处理

  • 生成8位随机数字OTP后,组装加密载荷,载荷必须包含三个核心字段:
    • OTP对应的用户唯一标识(比如用户邮箱、用户ID,避免OTP被跨账号冒用)
    • OTP过期时间戳(一般设为生成后3-5分钟,精确到毫秒)
    • 生成的8位OTP明文
  • 用服务端单独保管的对称密钥(推荐用AES-GCM模式,自带加密和完整性校验,密钥存在服务端配置文件中,绝对不能外泄)对上述载荷做对称加密,生成加密令牌。
  • 把加密令牌放到后续校验页的表单隐藏域,或者写入带HttpOnly、Secure属性的Cookie中返回给客户端,之后服务端直接丢弃内存中的OTP值,不做任何持久化、不写入Session。

注意:绝对不能把加密密钥下发到前端,一旦密钥泄露,整个校验机制完全失效。

OTP校验阶段处理

  • 用户提交OTP时,服务端同时拿到用户输入的OTP值、之前下发给客户端的加密令牌,以及当前请求对应的用户身份标识。
  • 用服务端本地存储的同一密钥解密加密令牌,逐层做校验:
    • 解密失败直接判定校验不通过,说明令牌被篡改
    • 解密后取出过期时间,和当前服务器时间对比,超时直接判定无效
    • 解密后取出用户标识,和当前请求的用户身份对比,不匹配直接判定无效
  • 上述校验全部通过后,再对比解密得到的OTP明文和用户输入的OTP,完全一致则校验通过,任意环节失败直接驳回,提示用户重新获取OTP。

安全加固建议

  • 不要使用ECB等不安全的加密模式,优先选AES-GCM这种带认证的加密模式,避免攻击者篡改加密令牌内容
  • OTP有效期不要设置过长,3-5分钟足够用户完成输入,缩小暴力破解的时间窗口
  • OTP校验失败超过3次直接作废当前令牌,要求用户重新发送OTP,避免暴力枚举
  • 禁止在服务端日志中打印OTP明文、加密密钥等敏感信息

核心逻辑伪代码参考

OTP生成逻辑

// 生成8位纯数字OTP
String otp = RandomStringUtils.randomNumeric(8);
// 构造载荷 格式:用户邮箱|过期时间戳|OTP明文
long expireAt = System.currentTimeMillis() + 5 * 60 * 1000;
String payload = String.format("%s|%d|%s", targetUserEmail, expireAt, otp);
// 用服务端密钥加密载荷生成令牌
String otpToken = AesGcmUtil.encrypt(payload, serverSecretKey);
// 令牌下发给前端,OTP发送到用户邮箱,服务端不存储任何相关数据
request.setAttribute("otpToken", otpToken);
sendOtpMail(targetUserEmail, otp);

OTP校验逻辑

// 从请求中取用户提交的参数
String inputOtp = request.getParameter("otp");
String submitToken = request.getParameter("otpToken");
String currentUser = getCurrentRequestUser(request); // 从请求上下文取当前关联的用户邮箱,不要信任前端传的用户标识

try {
    String decryptPayload = AesGcmUtil.decrypt(submitToken, serverSecretKey);
    String[] payloadItems = decryptPayload.split("\\|", 3);
    String tokenUser = payloadItems[0];
    long tokenExpire = Long.parseLong(payloadItems[1]);
    String realOtp = payloadItems[2];

    // 逐层校验
    if (!tokenUser.equals(currentUser)) {
        throw new IllegalArgumentException("身份信息不匹配");
    }
    if (System.currentTimeMillis() > tokenExpire) {
        throw new IllegalArgumentException("OTP已过期");
    }
    if (!realOtp.equals(inputOtp)) {
        throw new IllegalArgumentException("OTP输入错误");
    }
    // 校验通过,执行后续业务
    handleBusinessAfterVerify(currentUser);
} catch (Exception e) {
    request.setAttribute("errMsg", "OTP校验失败,请重新获取后重试");
    returnToVerifyPage();
}

内容的提问来源于stack exchange,提问作者Anonymous User

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:01:41