PHP实现登录错误次数限制

以下代码旨在实现逻辑,状态记录在cookie里不好,攻击者可以清除cookie,为了安全起见应将状态存储到缓存服务器,如redis

复制代码
<div style="width:100%;height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;">
    <form method="post" action='login.php?login=true'>
        <div>账号<input type="text" name="username" value="errorAccount"/></div>
        <div>密码<input type="password" name="password" value="errorAccount"/></div>
        <button>登录</button>
    </form>
    <div>
<?php

session_start();

$login = empty($_GET['login']) ? '' : trim($_GET['login']);
$username = empty($_POST['username']) ? '' : trim($_POST['username']);
$password = empty($_POST['password']) ? '' : trim($_POST['password']);

if ($login == 'true') {
    login();
}


function login() {
    
    global $username;
    global $password;
    
    $limitErrorTimeRange = 1; // 错误累计时间范围,分钟,在这个范围内超过规定次数则锁定一段时间才可登录
    $limitErrorCount = 5; // 限制连续登录错误次数,时间范围内连续错误满此次数后锁定一段时间才可登录
    $lockTime = 2; // 超限后锁定时长,分钟
    
    $userLoginState = array();
    // 初始化用户登录情况全局变量
    if (!isset($_SESSION['USER_LOGIN_ERROR_STATE'])) {
        $_SESSION['USER_LOGIN_ERROR_STATE'] = array(
            // 用username作为key,存当前用户的状态信息
            $username => array(
                'prevLoginErrorTime' => 0, // 上次登录错误时间戳(秒)
                'errorCount' => 0 // 时间范围内累计错误次数
            )
        );
    }
    // 得到当前用户的状态信息
    $userLoginState = $_SESSION['USER_LOGIN_ERROR_STATE'][$username];
    // print_r($userLoginState);
    // echo '<br/>';
    
    $userPrevLoginErrorTime = $userLoginState['prevLoginErrorTime'];
    $userErrorCount = $userLoginState['errorCount'];
    
    $loginCheck = true;
    
    // 若上次错误次数超限则进行解除判定
    if ($userErrorCount >= $limitErrorCount) {
        // 还未到解禁时间,返回限制倒计时提示
        // 计算锁定剩余分钟数
        $lockSurplusMinutes = ceil((($userPrevLoginErrorTime + $lockTime * 60 - time()) / 60));
        if ($lockSurplusMinutes > 0) {
            echo '你因登录失败次数过多已被锁定,请于' . $lockSurplusMinutes . '分钟后再登录!';
            return; // 必须return,防止下面代码修改信息
        }
        // 若已超锁定时长则允许重新登录(重新计数)
        else {
            $userErrorCount = 0;
            
            // 登录验证
            if ($username != 'user' && $password != '123') {
                $loginCheck = false;
                echo '1 登录失败<br/>';
            } else {
                echo '1 登录成功<br/>';
            }
        }
    }
    // 未超过错误次数限制
    else {
        // 若上次登录已超过累计时间范围则允许登录并重新开启一轮累计
        if (time() - $userPrevLoginErrorTime > $limitErrorTimeRange * 60) {
            $userErrorCount = 0;
        }
        
        // 登录验证
        if ($username != 'user' && $password != '123') {
            $loginCheck = false;
            echo '登录失败<br/>';
        } else {
            echo '登录成功<br/>';
        }
    }
    
    if (!$loginCheck) {
        // 验证不通过,错误次数+1
        $userErrorCount = $userErrorCount + 1;
        
    } else {
        // 验证通过,重置错误次数
        $userErrorCount = 0;
    }
    
    echo $userErrorCount . '<br/>';
    
    // 更新用户登录错误信息
    $_SESSION['USER_LOGIN_ERROR_STATE'][$username]['prevLoginErrorTime'] = time(); //
    $_SESSION['USER_LOGIN_ERROR_STATE'][$username]['errorCount'] = $userErrorCount;
    
    // echo '<br/>';
    // print_r($_SESSION['USER_LOGIN_ERROR_STATE']);
                
                
    // echo 'ahah<br>';
}
?>

    </div>
</div>
复制代码

 

posted @   jsper  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示