Quick and easy flood protection?

后端 未结 7 1821
忘了有多久
忘了有多久 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:20

    You don't need to go through the whole record file. Instead:

    <?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 *");
    }
    
    0 讨论(0)
  • 2020-12-29 12:21

    If you want to stop flooding a search page you can try it like this way:

    $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 search 10 times under e.g. 2 seconds he will be stopped!

    0 讨论(0)
  • 2020-12-29 12:25

    Another way to do this is to write a hidden form input to the page (that calls like.php) using jQuery. A bot won't be using javascript so your hidden form field won't exist.

    Check for the hidden field (assign it a value and a name) and if it exists, then hit the database with the request.

    Another way; code a hidden element into the page (<input style='display:none;' name='nospam' value='' />). A bot will auto-fill every field in the form, so you just check if this field is populated - a user can't see it so you know it's a bot if you've got content there.

    Set the style (display:none;) using jQuery tho... again, a bot won't see the jQuery, so it will think this is a legit form input.

    You may want to specify a 'this page requires javascript to run' notice somewhere for the user. Some alternative suggestions. After all - you said 'simple' ;)

    0 讨论(0)
  • 2020-12-29 12:26

    I thought about using sessions, like have a session that contains a timestamp that gets checked every time they send data to like.php

    This won't stop bots as they can receive and send the same cookies that users do.

    You should really have users logging into such a system. Seems to be worth protecting access. You could also consider limiting posts per minute per ip but multiple bots could still send many spam messages.

    If you don't want to implement a login then many sites use captcha to try and cut down on such attempts.

    http://www.phpcaptcha.org/

    0 讨论(0)
  • 2020-12-29 12:28

    Session is the easiest to do this, and has the least overhead as well. You can store two bits of data in the session, timestamp of last post, and the ip the post is comming from. Here is how you check legitimacy then:

    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
    
    0 讨论(0)
  • 2020-12-29 12:32

    Use a token. You generate the token and add it to the page originating the request. In like.php you verify that the request contains a valid token, which means it comes from your page instead of an external one POSTing directly.

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