Quick and easy flood protection?

I have a website where a user sends a message using AJAX to a file called like.php . In this file, the user's message is sent to the database and then sends the link to the user. In my Javascript code, I turned off the text box that the user enters when he sends an AJAX request.

The only problem is that an attacker could just constantly send POST requests to like.php and flood my database. Therefore, I would like to implement simple flood protection.

I really do not want the problem with another database table to register the IP addresses of users and such ... as if they were flooding my site, there will be a lot of read / write database slowing it down. I was thinking about using sessions, for example, a session that contains a timestamp that is checked every time they send data to like.php , and if the current time before the timestamp allows them to add data to the database, otherwise send a message about the error and block them. If they are allowed to enter something into the database, update their session with a new timestamp.

What do you think? Would this be a better way to do this or are there simpler alternatives?

Thanks for any help. :)

+7
php protection spam
source share
7 answers

Use a token. You generate a token and add it to the page coming from the request. In like.php you confirm that the request contains a valid token, which means that it comes from your page and not directly from external POSTing.

+5
source share

The session is easiest to do and has the lowest cost. You can store two bits of data in a session, the timestamp of the last message, and the ip from which the message is sent. Here's how you check the validity:

 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 
+7
source share

Another way to do this is to write a hidden form input to the page (which calls like.php) using jQuery. The bot will not use javascript, so your hidden form field will not exist.

Check the hidden field (give it a value and a name), and if it exists, then click on the database with the request.

Another way; enter the hidden element in the page ( <input style='display:none;' name='nospam' value='' /> ). The bot will automatically fill in each field in the form, so you just check if this field is filled in - the user cannot see it, so you know that this is a bot if you have content there.

Set the style (display: none;) using jQuery tho ... again, the bot will not see jQuery, so it will assume that this is a legitimate form input.

You might want to indicate that “this page requires javascript to run” a notification somewhere for the user. Some alternative suggestions. In the end, you said "just";)

+3
source share

You do not need to go through the entire recording file. Instead of this:

 <?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); } 

Usage example:

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

Well, I made a script to process it only for basic requests (without session requests or other requests that do not call the kernel). If you look at google, you will find scripts / classes that will kill your server due to heavy loads every time. The fact that many use SESSIONS and, possibly, ALSO SQL / Database, will allow you to get flood protection as a killer server. Also, the fact that SESSIONs need a Cookie (or GET SID) so you can easily manage SESSIONs to get a new SESSION identifier.

My function is text based and does simple processing. The bad news is that you may have to use CronJob to remove ips from time to time. Compared to other scenarios, it is about 10 * faster (and more than sessions).

I don’t know if this is really useful .;) You might want to change the rpm value to a lower one or /, and also to 200 req. My parameter is a ban for a bot that performs interval requests in <= 6 seconds.

 <?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); } } } } 

Edit: my way to check request time was with microtime and simulate 10'000 users. I ask google and tested (as an example) http://technitip.net/simple-php-flood-protection-class

So I don’t know what should be there simply? You have about 3 SQL queries at a time, for example:

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

You may have more features, but all legitimate users do not use servertime .;)

+2
source share

I was thinking about using sessions, for example having a session containing a timestamp that is checked every time they send data to a like.php file

This will not stop the bots, as they can receive and send the same cookies as users.

You really need users to register in such a system. It seems worth protecting access. You can also consider limiting messages per minute per ip, but several bots can send a lot of spam messages.

If you do not want to implement a login, many sites use captcha to try to reduce such attempts.

http://www.phpcaptcha.org/

0
source share

If you want to stop filling the search page, you can try it as follows:

 $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']; 

So, if your visitor is 10 times under that, 2 seconds he will be stopped!

0
source share

All Articles