账号锁定必要性
账号登录过程中最好添加一个安全登录次数限制的机制,防止有人恶意尝试登录。
账号登录失败次数账号锁定机制的必要性在于,它可以防止恶意攻击者通过暴力破解等方式尝试登录系统。如果限制可以执行的失败登录尝试次数,则几乎可以消除此类攻击的有效性。
在实际应用中,可以通过记录用户名和密码验证失败的次数来实现账户锁定机制。具体来说,需要针对每一个用户记录登录失败的次数nLock和锁定账户的到期时间releaseTime。这些信息可以存储在mysql、文件中或redis中等,完全取决于你对你所处的应用架构适用性的判断。
整体实现思路
用户登录失败后,需要记录登录失败日志并进行缓存。在缓存中,存放了登录失败的时间信息,思路是以天为单位进行存储。具体的时间间隔可以根据实际需求进行调整。
在登录过程中,需要先判断用户输入的登录账号是否正确。然后,再对当天登录失败的次数进行判断。如果超过设定的阈值,则直接返回账号被锁定的消息。
实现细节
项目比较老,基于thinkphp3.2的,用文件缓存进行登录状态记录
缓存的数组包含三个属性
$errorLog =array(
'n' => 2, //登录失败次数
't' => '2023-06-09', //登录失败日期记录
't2' =>array('2023-06-08','2023-06-09'), //所有有过登录失败记录的日期
);
登录校验函数
/**
* 用户登录信息检测
* $logInfo=array(
* 'userid'=>'', //账号
* 'pwd'=>'', //密码
* )
*/
if (!function_exists('checkLogin')) {
function checkLogin($logInfo = array())
{
$userid = $logInfo['userid'] ? trim($logInfo['userid']) : '';
$pwd = $logInfo['pwd'] ? trim($logInfo['pwd']) : '';
// 当天登录失败次数超过设置的最大值
// C('MAX_ERROR_LOGNUM') 是登录失败的阙值,可以根据情况直接换掉或者改成自己的调用方式
if (getErrorLog($userid) >= C('MAX_ERROR_LOGNUM')) {
return array('status' => 0, 'info' => '登录失败次数过多,账号被锁定,请联系管理员');
}
// Login这个地方放登录检验代码,实际情况中可以抽离也可以直接把判断逻辑写在这里
// 返回值true登录成功,false登录失败
$loginResult=Login($userid,$pwd);
if (!$loginResult == false) {
// 登录日志记录
$num = recordErrorLog($user['userid']);
if ($num < C('MAX_ERROR_LOGNUM')) {
return array('status' => 0, 'info' => '账号或密码错误,您还有' . (C('MAX_ERROR_LOGNUM') - $num) . '次机会');
} else {
return array('status' => 0, 'info' => '失败次数过多被锁定,请联系管理员');
}
}
// 根据自己情况进行登录状态记录,cookie,session,token等等
return array('status' => 1, 'info' => '登录成功');
}
}
登录失败日志记录,返回当天失败次数
/**
* 登录失败日志记录,返回当天失败次数
*/
if (!function_exists('recordErrorLog')) {
function recordErrorLog($userid)
{
$errorLog = F('UserLogError/' . $userid); //用F函数做文件缓存,缓存的名字就是用户的登录账号,简单粗暴。
$nd = date('Y-m-d');
if ($errorLog) {
if ($nd == $errorLog['t']) {
$errorLog['n']++;
} else {
$errorLog['t2'][] = $nd;
$errorLog = ['n' => 1, 't' => $nd, 't2' => $errorLog['t2']];
}
} else {
$errorLog = ['n' => 1, 't' => $nd, 't2' => [$nd]];
}
F('UserLogError/' . $userid, $errorLog);
return $errorLog['n'];
}
}
获取账号当天失败次数
/**
* 获取账号当天失败次数
*/
if (!function_exists('getErrorLog')) {
function getErrorLog($userid)
{
$errorLog = F('UserLogError/' . $userid);
return ($errorLog['t'] == date('Y-m-d')) ? $errorLog['n'] : 0;
}
}
小结
上面的代码比较简单,逻辑也不难理解,关键在于把登录状态记录下来,然后根据特定日期和账号进行判断,也可以根据情况实现一个更为复杂的登录失败校验机制的函数,比如限制前5次登录失败后锁定30分钟再登录,如果30分钟后又失败两次,则锁定1小时,半小时后再失败两次则锁定2小时,4小时,8小时…等等。