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

PHP MySQL PDO OTP/2FA登录问题:错误OTP仍跳转home.php

问题排查:OTP验证不匹配仍跳转首页的问题

问题描述

我用PHP MySQL PDO实现了OTP/2FA登录功能,整体运行正常,但存在异常:在OTP输入框填写任意数字时,即便该数字与数据库中的OTP不匹配,页面仍会跳转到home.php。请帮忙排查代码中的问题或缺失项。

原代码

if(!empty($_POST["authenticate"]) && $_POST["otp"]!='') {
    
    try {
        $otp_code = $_POST["otp"];
        
        $statement = $db->prepare("SELECT * FROM $table4 WHERE otp=:otp_code AND expired!=1 AND NOW() <= DATE_ADD(created, INTERVAL 10 MINUTE)");
            
        $statement->bindParam(":otp_code", $otp_code);
            
        $statement->execute();
        $count=$statement->rowCount();
        if($count<1)
            {
            
            $data = [
                'expired' => 1,
                'otp_code' => $otp_code,
            ];
            
            $sql = "UPDATE $table4 SET expired=:expired WHERE otp=:otp_code";
            $stmt= $db->prepare($sql);
            $stmt->execute($data);
            
            $_SESSION['otp_code'] = $otp_code;
            
            header("Location: home.php");
        
        } else {
            $errorMessage = "Invalid Security Code!";
        }
        
    } catch (PDOException $e) {
        echo "Error : Check your error message.";
        file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
    }
    
} else if (!empty($_POST["otp"])) {
    $errorMessage = "Enter Security Code!";
}

问题核心

条件判断逻辑完全写反了:

  • 当前代码中if($count<1)的逻辑是「数据库中找不到匹配的有效OTP时」,执行跳转首页的操作
  • 正确逻辑应该是「找到匹配的有效OTP时」才允许跳转,不匹配时提示错误

修复后的代码

if(!empty($_POST["authenticate"]) && $_POST["otp"]!='') {
    
    try {
        $otp_code = $_POST["otp"];
        
        $statement = $db->prepare("SELECT * FROM $table4 WHERE otp=:otp_code AND expired!=1 AND NOW() <= DATE_ADD(created, INTERVAL 10 MINUTE)");
            
        $statement->bindParam(":otp_code", $otp_code);
            
        $statement->execute();
        $count=$statement->rowCount();
        
        // 修正条件:找到匹配的有效OTP才执行登录逻辑
        if($count>0)
        {
            // 标记该OTP为已过期,防止重复使用
            $data = [
                'expired' => 1,
                'otp_code' => $otp_code,
            ];
            
            $sql = "UPDATE $table4 SET expired=:expired WHERE otp=:otp_code";
            $stmt= $db->prepare($sql);
            $stmt->execute($data);
            
            $_SESSION['otp_code'] = $otp_code;
            
            header("Location: home.php");
            // 跳转后必须终止脚本执行,避免后续代码运行
            exit;
        
        } else {
            $errorMessage = "Invalid Security Code!";
        }
        
    } catch (PDOException $e) {
        echo "Error : Check your error message.";
        file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
    }
    
} else if (!empty($_POST["otp"])) {
    $errorMessage = "Enter Security Code!";
}

额外优化建议

  • 跳转后添加exit;,防止脚本继续执行引发不必要的问题
  • 确保脚本最顶部已调用session_start(),保证SESSION正常工作
  • 如果OTP表关联了用户ID,建议在UPDATE语句中加入用户ID条件,避免同一OTP被不同用户使用时误标记过期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 13:22:17