Asked  7 Months ago    Answers:  5   Viewed   31 times

I want to prevent my script, from being flooded - if user hit F5 it is executing the script every time.

I want to prevent from this and allow one script execution per 2 seconds, is there any solution for that?

 Answers

18

You can use memcache to do this ..

Simple Demo Script

$memcache = new Memcache ();
$memcache->connect ( 'localhost', 11211 );
$runtime = $memcache->get ( 'floodControl' );

if ((time () - $runtime) < 2) {
    die ( "Die! Die! Die!" );
} 

else {
    echo "Welcome";
    $memcache->set ( "floodControl", time () );
}

This is just a sample code .. there are also other thing to consider such as

A. Better IP address detection (Proxy , Tor )

B. Current Action

C. Maximum execution per min etc ...

D. Ban User after max flood etc

EDIT 1 - Improved Version

Usage

$flood = new FloodDetection();
$flood->check();

echo "Welcome" ;

Class

class FloodDetection {
    const HOST = "localhost";
    const PORT = 11211;
    private $memcache;
    private $ipAddress;

    private $timeLimitUser = array (
            "DEFAULT" => 2,
            "CHAT" => 3,
            "LOGIN" => 4 
    );
    private $timeLimitProcess = array (
            "DEFAULT" => 0.1,
            "CHAT" => 1.5,
            "LOGIN" => 0.1 
    );

    function __construct() {
        $this->memcache = new Memcache ();
        $this->memcache->connect ( self::HOST, self::PORT );
    }

    function addUserlimit($key, $time) {
        $this->timeLimitUser [$key] = $time;
    }

    function addProcesslimit($key, $time) {
        $this->timeLimitProcess [$key] = $time;
    }

    public function quickIP() {
        return (empty ( $_SERVER ['HTTP_CLIENT_IP'] ) ? (empty ( $_SERVER ['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER ['REMOTE_ADDR'] : $_SERVER ['HTTP_X_FORWARDED_FOR']) : $_SERVER ['HTTP_CLIENT_IP']);
    }

    public function check($action = "DEFAULT") {
        $ip = $this->quickIP ();
        $ipKey = "flood" . $action . sha1 ( $ip );

        $runtime = $this->memcache->get ( 'floodControl' );
        $iptime = $this->memcache->get ( $ipKey );

        $limitUser = isset ( $this->timeLimitUser [$action] ) ? $this->timeLimitUser [$action] : $this->timeLimitUser ['DEFAULT'];
        $limitProcess = isset ( $this->timeLimitProcess [$action] ) ? $this->timeLimitProcess [$action] : $this->timeLimitProcess ['DEFAULT'];

        if ((microtime ( true ) - $iptime) < $limitUser) {
            print ("Die! Die! Die! $ip") ;
            exit ();
        }

        // Limit All request
        if ((microtime ( true ) - $runtime) < $limitProcess) {
            print ("All of you Die! Die! Die! $ip") ;
            exit ();
        }

        $this->memcache->set ( "floodControl", microtime ( true ) );
        $this->memcache->set ( $ipKey, microtime ( true ) );
    }

}
Wednesday, March 31, 2021
 
iceduck
answered 7 Months ago
12

Use the final keyword.

Wednesday, March 31, 2021
 
linjuming
answered 7 Months ago
23

Some ideas:

  1. Server-side only. The easiest way to do this is to use session variables (like $_SESSION) so that all the data kept on the server side, but managing it and keeping separate tabs a user might have open separate can get a little tricky. This option prevents the user from seeing or editing the information.

  2. Make the client carry an encrypted blob. Take all your "temporary but protected" data, combine it somehow (e.g. JSON) and then encrypt* the whole thing with a secret key known only to the server. Base64 the result and put that into the hidden field value. (Note that for a high-security application, you'll also want to work an HMAC into this process, which validates that the ciphertext hasn't been tinkered with.) This option also prevents the user from seeing or editing the information, but makes it easier to handle cases where one user has many tabs open.

  3. Still use not-so-secret hidden input fields, but add an anti-tampering mechanism. So when the page is being generated, take all of your existing "protected" variables, combine them somehow with a server-side secret value, and hash [correction: HMAC] them. Store the hash in its own hidden field. Then after the user submits, you repeat the process and check if the hash matches. If it doesn't, have everything error with security-violation page.

*As with all cryptography, doing this the "right" way can be tricky and depends a lot on how you encrypt/verify. There are lot of pitfalls in terms of ciphers and cipher-modes etc.

Finally, remember that preventing people from modifying it doesn't mean a user can't copy everything and re-use it later or under another account, unless you take steps to include a "timestamp" etc.

Wednesday, March 31, 2021
 
ariel
answered 7 Months ago
11

popen() or proc_open is still an option, you just need to avoid sleep() and manage the execution time yourself.

$end = time() + 20;
while (!feof($stream) && (time() < $end)) {

    $output .= fread($stream);

The popen stream should be set up non-blocking still:

stream_set_blocking($stream, 0);

Polling the output like this might be still a bit straining, so you should consider adding a small time_nanosleep() anyway. The runtime is limited to max 20 seconds by the time()<$end check in either case.

Wednesday, March 31, 2021
 
revive
answered 7 Months ago
87

set_time_limit() does run globally, but it can be reset locally.

Set the number of seconds a script is allowed to run. If this is reached, the script returns a fatal error. The default limit is 30 seconds or, if it exists, the max_execution_time value defined in the php.ini.

When called, set_time_limit() restarts the timeout counter from zero. In other words, if the timeout is the default 30 seconds, and 25 seconds into script execution a call such as set_time_limit(20) is made, the script will run for a total of 45 seconds before timing out.

I've not tested it, but you may be able to set it locally, resetting when you leave the

<?php
set_time_limit(0);  // global setting

function doStuff()
{
    set_time_limit(10);   // limit this function
    //  stuff
    set_time_limit(10);   // give ourselves another 10 seconds if we want
    //  stuff
    set_time_limit(0);    // the rest of the file can run forever
}

// ....
sleep(900);
// ....
doStuff();  // only has 10 secs to run
// ....
sleep(900);
// ....

set_time_limit() ... Any time spent on activity that happens outside the execution of the script such as system calls using system(), stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real.

Wednesday, June 9, 2021
 
SubniC
answered 5 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :