Intereting Posts
Шифровать данные с помощью открытого ключа в c # и расшифровать данные с помощью закрытого ключа в php Сортировка многомерного массива, построенного из данных CSV, с использованием PHP как использовать phpfastcache? php Проверять строки широты / долготы в десятичном формате Отправить логическое значение в данных jQuery ajax Как обрезать текст с помощью PHP работать – из двух значений массива? Перенаправление на предыдущую страницу после входа в систему с помощью PHP Центральный вход с SAML и создание сайта для работы в качестве поставщика удостоверений Как обновить файл на Google Диске v3 PHP Пользовательский формат Jqgrid использует скобку (), если значение negatif Как я могу получить список статических переменных в классе? Просмотр хранилища фильтров на основе группы клиентов в Magento Передача нескольких переменных в представление? php удалить элемент из массива

Быстрая и простая защита от наводнений?

У меня есть сайт, на котором пользователь отправляет сообщение с использованием AJAX в файл с именем like.php . В этом файле сообщение пользователя отправляется в базу данных и затем отправляет ссылку пользователю. В моем коде Javascript я отключил текстовое поле, которое вводит пользователь, когда отправляет запрос AJAX.

Единственная проблема заключается в том, что злоумышленник может просто постоянно отправлять POST-запросы на like.php и наводнять мою базу данных. Поэтому я хотел бы реализовать простую защиту от наводнений.

Я действительно не хочу, чтобы проблема с другой таблицей базы данных регистрировала IP-адреса пользователей и т. Д., Как если бы они наводнили мой сайт, будет много чтения / записи базы данных, замедляющих ее. Я думал об использовании сеансов, например, о сеансе, который содержит like.php времени, которая проверяется каждый раз, когда они отправляют данные на like.php , и если текущее время до отметки времени позволяет им добавлять данные в базу данных, в противном случае отправлять ошибку и заблокировать их. Если им разрешено что-то вводить в базу данных, обновите их сеанс новой меткой времени.

Как вы думаете? Будет ли это лучшим способом для этого или есть более простые альтернативы?

Спасибо за любую помощь. 🙂

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

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

 session_start(); if(isset($_SESSION['ip']) && $_SESSION['last_post'] + MININTERVAL < time()) die('too early'); $_SESSION['last_post'] = time(); $_SESSION['ip'] = $_SERVER['REMOTE_ADDR']; // store the message 

Другой способ сделать это – написать скрытый ввод формы на страницу (которая вызывает like.php) с помощью jQuery. Бот не будет использовать javascript, поэтому ваше скрытое поле формы не будет существовать.

Проверьте скрытое поле (присвойте ему значение и имя), и если он существует, нажмите на базу данных с запросом.

Другой путь; код скрытого элемента на странице ( <input style='display:none;' name='nospam' value='' /> ). Бот будет автоматически заполнять каждое поле в форме, поэтому вы просто проверяете, заполнено ли это поле – пользователь не может его увидеть, поэтому вы знаете, что это бот, если у вас есть контент.

Установите стиль (display: none;), используя jQuery tho … снова, бот не увидит jQuery, поэтому он будет считать, что это законный ввод формы.

Возможно, вам захочется указать, что «эта страница требует, чтобы javascript запускал» уведомление где-то для пользователя. Некоторые альтернативные предложения. В конце концов – вы сказали «просто»;)

Вам не нужно проходить весь файл записи. Вместо:

 <?php define("FLOODPOOL", "."); define("FLOODPOOL_LIMIT", 30); define("FLOODPOOL_DURATION", 60 * 60 * 24); define("FLOODPOOL_AUTOCLEAN", true); // Record and check flood. // Return true for hit. function floodpool_check($id){ $fp = fopen(FLOODPOOL . DIRECTORY_SEPARATOR . 'fp_' . basename($id), 'a+'); fwrite($fp, pack('L', time())); if(fseek($fp, -4 * FLOODPOOL_LIMIT, SEEK_END) === -1) { return false; } $time = reset(unpack('L', fread($fp, 4))); fclose($fp); if(time() - $time < FLOODPOOL_DURATION) { if(FLOODPOOL_AUTOCLEAN){ @floodpool_clean(); } return true; } return false; } // Clean the pool. function floodpool_clean(){ $handle = opendir(FLOODPOOL); while(false!==($entry=readdir($handle))){ $filename = FLOODPOOL . DIRECTORY_SEPARATOR . $entry; if(time() - filectime($filename) > FLOODPOOL_DURATION && substr($entry, 0, 3) === 'fp_'){ unlink($filename); } } closedir($handle); } в <?php define("FLOODPOOL", "."); define("FLOODPOOL_LIMIT", 30); define("FLOODPOOL_DURATION", 60 * 60 * 24); define("FLOODPOOL_AUTOCLEAN", true); // Record and check flood. // Return true for hit. function floodpool_check($id){ $fp = fopen(FLOODPOOL . DIRECTORY_SEPARATOR . 'fp_' . basename($id), 'a+'); fwrite($fp, pack('L', time())); if(fseek($fp, -4 * FLOODPOOL_LIMIT, SEEK_END) === -1) { return false; } $time = reset(unpack('L', fread($fp, 4))); fclose($fp); if(time() - $time < FLOODPOOL_DURATION) { if(FLOODPOOL_AUTOCLEAN){ @floodpool_clean(); } return true; } return false; } // Clean the pool. function floodpool_clean(){ $handle = opendir(FLOODPOOL); while(false!==($entry=readdir($handle))){ $filename = FLOODPOOL . DIRECTORY_SEPARATOR . $entry; if(time() - filectime($filename) > FLOODPOOL_DURATION && substr($entry, 0, 3) === 'fp_'){ unlink($filename); } } closedir($handle); } 

Пример использования:

 if(floodpool_check($_SERVER['REMOTE_ADDR'])){ header("HTTP/1.1 429 Too Many Requests"); exit("Hit some *"); } 

Ну, я сделал сценарий для обработки его только для основных запросов (без запросов на сеанс или других запросов, которые не называют ядро). Если вы посмотрите на google, вы найдете скрипты / классы, которые будут убивать ваш сервер из-за больших нагрузок каждый раз. Тот факт, что многие используют СЕССИИ и, возможно, ТАКЖЕ SQL / Database, позволит вам получить защиту от наводнений в качестве сервера-убийцы. Также тот факт, что SESSIONs нужен Cookie (или GET SID), чтобы вы могли легко управлять SESSIONs, чтобы получить новый идентификатор SESSION.

Моя функция основана на тексте и делает простое управление. Плохо то, что вам, возможно, придется использовать CronJob для удаления ips время от времени. По сравнению с другими сценариями он примерно на 10 * быстрее (и больше, чем сеансы).

Я не знаю, действительно ли это действительно полезно. 😉 Возможно, вам захочется изменить значение rpm на меньшее или /, а также на 200 req. Моя настройка – это запрет для бота, выполняющего интервальные запросы в <= 6 секунд.

 <?php function ht_request_limiter() { if (!isset($_SERVER['REMOTE_ADDR'])) { return; } // Maybe its impossible, however we check it first if (empty($_SERVER['REMOTE_ADDR'])) { return; } // Maybe its impossible, however we check it first $path = '/your/path/ipsec/'; // I use a function to validate a path first and return if false... $path = $path.$_SERVER['REMOTE_ADDR'].'.txt'; // Real file path (filename = <ip>.txt) $now = time(); // Current timestamp if (!file_exists($path)) { // If first request or new request after 1 hour / 24 hour ban, new file with <timestamp>|<counter> if ($handle = fopen($path, 'w+')) { if (fwrite($handle, $now.'|0')) { chmod($path, 0700); } // Chmod to prevent access via web fclose($handle); } } else if (($content = file_get_contents($path)) !== false) { // Load existing file $content = explode('|',$content); // Create paraset [0] -> timestamp [1] -> counter $diff = (int)$now-(int)$content[0]; // Time difference in seconds from first request to now if ($content[1] == 'ban') { // If [1] = ban we check if it was less than 24 hours and die if so if ($diff>86400) { unlink($path); } // 24 hours in seconds.. if more delete ip file else { header("HTTP/1.1 503 Service Unavailable"); exit("Your IP is banned for 24 hours, because of too many requests."); } } else if ($diff>3600) { unlink($path); } // If first request was more than 1 hour, new ip file else { $current = ((int)$content[1])+1; // Counter + 1 if ($current>200) { // We check rpm (request per minute) after 200 request to get a good ~value $rpm = ($current/($diff/60)); if ($rpm>10) { // If there was more than 10 rpm -> ban (if you have a request all 5 secs. you will be banned after ~17 minutes) if ($handle = fopen($path, 'w+')) { fwrite($handle, $content[0].'|ban'); fclose($handle); // Maybe you like to log the ip once -> die after next request } return; } } if ($handle = fopen($path, 'w+')) { // else write counter fwrite($handle, $content[0].'|'.$current .''); fclose($handle); } } } } 

Изменить: мой способ проверить время запроса был с microtime и имитировать 10'000 пользователей. Я прошу Google и протестировал (как пример) http://technitip.net/simple-php-flood-protection-class

Значит, я не знаю, что должно быть там просто? Вы имеете примерно 3 запроса SQL одновременно:

 $this -> user_in_db($ip)) $this->user_flooding($ip); $this->remove_old_users(); 

Это может быть больше функций, но все законные пользователи используют серебро без изменений. 😉

Я думал об использовании сеансов, например, о сеансе, который содержит отметку времени, которая проверяется каждый раз, когда они отправляют данные в like.php

Это не остановит ботов, поскольку они могут получать и отправлять те же файлы cookie, что и пользователи.

Вам действительно нужно, чтобы пользователи регистрировались в такой системе. Кажется, стоит защищать доступ. Вы также можете рассмотреть вопрос о ограничении сообщений в минуту за ip, но несколько ботов могут отправлять много спам-сообщений.

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

http://www.phpcaptcha.org/

Если вы хотите прекратить наводнение поисковой страницы, вы можете попробовать ее следующим образом:

 $flood_protection_interval = 2; session_start(); if( isset($_SESSION['ip']) && $_SESSION['counter'] > 10 && $_SESSION['last_post'] + $flood_protection_interval > time() ){ // $_SESSION['counter'] = 0; // Use this if you want to reset counter die("<pre>\n\n\n\t<b>FLOOD PROTECTION</b>"); } $_SESSION['counter']++; $_SESSION['last_post'] = time(); $_SESSION['ip'] = $_SERVER['REMOTE_ADDR']; 

Так что если ваш посетитель будет искать 10 раз, например, через 2 секунды, он будет остановлен!