Вы не можете просто предотвратить DoS-атаки, связав регулирование до одного IP-адреса или имени пользователя. Черт, вы даже не можете предотвратить попытки быстрого входа в систему с помощью этого метода.
Почему? Поскольку атака может охватывать несколько IP-адресов и учетных записей пользователей, чтобы обойти ваши попытки регулирования.
Я уже писал в другом месте, что в идеале вы должны отслеживать все неудачные попытки входа на сайт и связывать их с отметкой времени, возможно:
CREATE TABLE failed_logins (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(16) NOT NULL,
ip_address INT(11) UNSIGNED NOT NULL,
attempted DATETIME NOT NULL,
INDEX `attempted_idx` (`attempted`)
) engine=InnoDB charset=UTF8;
Краткое примечание к полю ip_address: вы можете хранить данные и извлекать данные соответственно с помощью INET_ATON () и INET_NTOA (), которые по сути равносильны преобразованию IP-адреса в целое число без знака и из него.
# example of insertion
INSERT INTO failed_logins SET username = 'example', ip_address = INET_ATON('192.168.0.1'), attempted = CURRENT_TIMESTAMP;
# example of selection
SELECT id, username, INET_NTOA(ip_address) AS ip_address, attempted;
Определите определенные пороговые значения задержки на основе общего числа неудачных входов в систему за указанный промежуток времени (15 минут в этом примере). Вы должны основывать это на статистических данных, извлеченных из вашей таблицы failed_logins
, так как она будет меняться со временем в зависимости от количества пользователей и количества из них, которые смогут вспомнить (и ввести) свой пароль.
> 10 failed attempts = 1 second
> 20 failed attempts = 2 seconds
> 30 failed attempts = reCaptcha
Запросите таблицу при каждой неудачной попытке входа в систему, чтобы найти количество неудачных попыток входа в систему за определенный период времени, скажем, 15 минут:
SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);
Если количество попыток в течение заданного периода времени превышает ваш лимит, либо принудительно дросселируйте, либо заставьте всех пользователей использовать капчу (т.е. reCaptcha), пока количество неудачных попыток за указанный период времени не станет меньше порогового значения ,
// array of throttling
$throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');
// retrieve the latest failed login attempts
$sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$result = mysql_query($sql);
if (mysql_affected_rows($result) > 0) {
$row = mysql_fetch_assoc($result);
$latest_attempt = (int) date('U', strtotime($row['attempted']));
// get the number of failed attempts
$sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';
$result = mysql_query($sql);
if (mysql_affected_rows($result) > 0) {
// get the returned row
$row = mysql_fetch_assoc($result);
$failed_attempts = (int) $row['failed'];
// assume the number of failed attempts was stored in $failed_attempts
krsort($throttle);
foreach ($throttle as $attempts => $delay) {
if ($failed_attempts > $attempts) {
// we need to throttle based on delay
if (is_numeric($delay)) {
$remaining_delay = time() - $latest_attempt - $delay;
// output remaining delay
echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
} else {
// code to display recaptcha on login form goes here
}
break;
}
}
}
}
Использование reCaptcha при определенном пороге гарантирует, что атака с нескольких фронтов будет остановлена, и у обычных пользователей сайта не будет значительной задержки для законных неудачных попыток входа в систему.