Quick and easy flood protection?

后端 未结 7 1822
忘了有多久
忘了有多久 2020-12-29 11:51

I have a site where a user submits a message using AJAX to a file called like.php. In this file the users message is submitted to a database and it then sends a

相关标签:
7条回答
  • 2020-12-29 12:32

    Well I made a script to handle it for core requests only (no session requests or other requests who aren't calling the core). If you have a look to google you'll find scripts/classes which will kill your server because of high loads every time. The fact, that many use SESSIONs and maybe ALSO SQL/Database will let you get a flooding protection as a server-killer. Also the fact that SESSIONs need a Cookie (or a GET SID) so you can manipulate SESSIONs easy to get a new SESSION ID.

    My function is text-based and do a simple handling. The bad thing is that you maybe have to use a CronJob to delete ips from time to time. Comparing to other scripts its about 10* faster (and more save than sessions).

    I don't know if its really useful at all. ;) You maybe like to change the rpm value to less or/and also the 200 req. My setting is a ban for a bot doing 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 test the request time was with microtime and simulate 10'000 users. I ask google and tested (as example) http://technitip.net/simple-php-flood-protection-class

    So I don't know what should be simple there? You have about 3 SQL Requests at one time like:

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

    It maybe supply more functions, but all legit users use servertime for nothing. ;)

    0 讨论(0)
提交回复
热议问题