スロットルを単一のIPまたはユーザー名に連鎖させることによってDoS攻撃を単純に防ぐことはできません。この方法を使用して、迅速なログイン試行を実際に防ぐことさえできません。
なんで? スロットルの試みを回避するために、攻撃は複数の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を使用すると、複数のフロントからの攻撃が阻止され、通常のサイトユーザーが正当なログイン試行の失敗によって大幅な遅延が発生することはありません。