Как я могу ограничить попытки входа пользователя в PHP - PullRequest
53 голосов
/ 19 января 2010

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

Рекомендация № 1: небольшая задержка, которая увеличивается с увеличением количества неудачных попыток, например:

1 неудачная попытка = без задержки
2 неудачные попытки = задержка 2 с
3 неудачные попытки = задержка 4 с
4 неудачные попытки = задержка 8 секунд
5 неудачных попыток = 16 секундная задержка
и т. д.

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

Мне любопытно, как я мог бы реализовать что-то подобное для моей системы входа в PHP?

Ответы [ 12 ]

1 голос
/ 19 января 2010

Я обычно создаю историю входа и таблицы попыток входа. В таблице попыток будут записываться имя пользователя, пароль, IP-адрес и т. Д. Выполните запрос к таблице, чтобы узнать, нужно ли откладывать. Я бы рекомендовал полностью блокировать попытки больше 20 в данный момент времени (например, час).

0 голосов
/ 05 октября 2012

cballuo дал отличный ответ. Я просто хотел вернуть услугу, предоставив обновленную версию, которая поддерживает mysqli. Я немного изменил столбцы таблицы / поля в sqls и других мелких вещах, но это должно помочь любому, кто ищет аналог mysqli.

function get_multiple_rows($result) {
  $rows = array();
  while($row = $result->fetch_assoc()) {
    $rows[] = $row;
  }
  return $rows;
}

$throttle = array(10 => 1, 20 => 2, 30 => 5);

$query = "SELECT MAX(time) AS attempted FROM failed_logins";    

if ($result = $mysqli->query($query)) {

    $rows = get_multiple_rows($result);

$result->free();

$latest_attempt = (int) date('U', strtotime($rows[0]['attempted'])); 

$query = "SELECT COUNT(1) AS failed FROM failed_logins WHERE time > DATE_SUB(NOW(), 
INTERVAL 15 minute)";   

if ($result = $mysqli->query($query)) {

$rows = get_multiple_rows($result);

$result->free();

    $failed_attempts = (int) $rows[0]['failed'];

    krsort($throttle);
    foreach ($throttle as $attempts => $delay) {
        if ($failed_attempts > $attempts) {
                echo $failed_attempts;
                $remaining_delay = (time() - $latest_attempt) - $delay;

                if ($remaining_delay < 0) {
                echo 'You must wait ' . abs($remaining_delay) . ' seconds before your next login attempt';
                }                

            break;
        }
     }        
  }
}
...