Как отложить попытки входа в систему после слишком большого количества попыток (PHP) - PullRequest
7 голосов
/ 20 мая 2009

Я работаю над довольно большим веб-сайтом, построенным на PHP, у которого потенциально может быть много пользователей. Я ищу способ защитить экран входа в систему от автоматических попыток. Я уже включил проверку CAPTCHA в регистрационную форму, но хочу еще больше укрепить сайт.

Были похожие вопросы о StackOverflow, о которых я знаю, и я знаю, что могу реализовать это сам с нуля (сохранение попыток входа и их времени в БД), но мне не нравится этот путь:

  • Концептуально, я думаю, что эта логика принадлежит уровню веб-сервера / инфраструктуры, а не уровню приложения. Мне не нравится иметь эту логику и сложность в моем приложении
  • Я беспокоюсь о производительности, особенно на уровне базы данных.
  • В хорошем смысле, я ленивый, потому что не хочу создавать общую утилиту, подобную этой, с нуля

Любой совет приветствуется, я думаю, что я особенно ищу какой-то модуль Apache, который может это сделать. Моя платформа - PHP5 (с использованием CodeIgniter), Apache2, MySQL 5.

Ответы [ 3 ]

16 голосов
/ 20 мая 2009

обновление: не используйте sleep () для ограничения скорости! это вообще не имеет смысла. у меня нет лучшего решения под рукой.


хорошим началом будет просто sleep(1); после неудачной попытки входа в систему - легко реализовать, практически без ошибок.

1 секунда - это не так много для человека (особенно потому, что попытки входа в систему нередко случаются неудачно), но 1 секунда / попытка перебора ... sloooow! атака по словарю может быть другой проблемой, но она находится в том же домене.

если злоумышленник запускает слишком много соединений, чтобы обойти это, вы имеете дело с некой DOS-атакой. проблема решена (но теперь у вас есть другая проблема).

некоторые вещи, которые вы должны рассмотреть:

  • если вы блокируете учетные записи только для отдельных IP-адресов, могут возникнуть проблемы с частными сетями.
  • если вы блокируете учетные записи только на основе имени пользователя, возможны атаки типа «отказ в обслуживании» против известных имен пользователей
  • блокировка на основе IP / имени пользователя (где имя пользователя атаковано) может работать лучше

мое предложение: полная блокировка нежелательна (DOS), поэтому лучшей альтернативой будет: подсчет попыток входа для определенного имени пользователя с уникального IP-адреса. Вы можете сделать это с помощью простой таблицы failed_logins: IP/username/failed_attempts

, если не удается войти в систему, wait(failed_attempts); секунд. Каждые xx минут запускайте скрипт cron, который уменьшается на failed_logins:failed_attempts на единицу.

извините, я не могу предоставить готовое решение, но это должно быть тривиально для реализации.

хорошо, хорошо. вот псевдокод:

<?php
$login_success = tryToLogIn($username, $password);

if (!$login_success) {
    // some kind of unique hash
    $ipusr = getUserIP() . $username;

    DB:update('INSERT INTO failed_logins (ip_usr, failed_attempts) VALUES (:ipusr, 1) ON DUPLICATE KEY UPDATE failed_logins SET failed_attempts = failed_attempts+1 WHERE ip_usr=:ipusr', array((':ipusr' => $ipusr));

    $failed_attempts = DB:selectCell('SELECT failed_attempts WHERE ip_usr=:ipusr', array(':ipusr' => $ipusr));

    sleep($failed_attempts);
    redirect('/login', array('errorMessage' => 'login-fail! ur doin it rong!'));
}
?>

отказ от ответственности: это может не работать в определенных регионах. Последнее, что я услышал, было то, что в Азии есть целая страна NAT (также они все знают кунг-фу).

2 голосов
/ 20 мая 2009

Очень глупый непроверенный пример, но я думаю, вы найдете здесь основную идею).

if ($unlockTime && (time() > $unlockTime))
{
    query("UPDATE users SET login_attempts = 0, unlocktime = 0 ... ");
}
else
{
   die ('Your account is temporary locked. Reason: too much wrong login attempts.');
}
if (!$logged_in)
{
    $loginAttempts++;
    $unlocktime = 0;
    if ($loginAttempts > MAX_LOGIN_ATTEMPTS) 
    {
        $unlockTime = time() + LOCK_TIMEOUT;
    }
    query("UPDATE users SET login_attempts = $loginAttempts, unlocktime = $unlocktime ... ");
}

Извините за ошибки - я написал это через несколько секунд, объявление не проверял ... То же самое вы можете сделать по IP, по нику, по идентификатору сессии и т. Д. *

0 голосов
/ 20 мая 2009

Почему бы вам не подождать с «усилением» и «масштабированием» вашего приложения, пока у вас действительно не возникнет эта проблема? Скорее всего, сценарий состоит в том, что в приложении никогда не будет «много пользователей». Для меня это звучит как преждевременная оптимизация, чего-то, чего следует избегать.

  • Как только вы поймете, что боты злоупотребляют, укрепите регистрацию. Я бы на самом деле убрал капчу, пока вы не начнете получать> 1000 регистраций в день.
  • Как только у вас возникнут проблемы с производительностью, улучшите производительность, устранив реальные узкие места.
...