Manue Lelelexd
Manue Lelelexd

Reputation: 31

php blocks ips? is it worth the cost

this is my first post, hope to be posting the right content.

I designed this code, it blocks ips if the previous connection was made before a certain span of time and if this patron has been repeated x times (in the example code: if you have connected 10 times in less than 10 seconds in a row, in other words you are spending less than 10 seconds in each page you visit).

The questions:

Hope everything is clear. Thank you.

$ip = preg_replace('#[^0-9.]#', '', getenv('REMOTE_ADDR'));
$sql = db_query("SELECT * FROM `protect` WHERE `ip` LIKE '$ip' AND `blocked` LIKE 1 LIMIT 1");
$count = mysqli_num_rows($sql);
if($count != 0){
    echo "Too many connections";
    exit();
}
$sql = db_query("SELECT * FROM `protect` WHERE `ip` LIKE '$ip' LIMIT 1");
$count = mysqli_num_rows($sql);
if($count != 0){
    while ($row = mysqli_fetch_array($sql, MYSQLI_ASSOC)){
        $previousCon=$row["previousCon"];
        $counter = $row["counter"];
    }
    $timeSpan=time()-strtotime($previousCon);
    if($timeSpan>10){
        $sql = db_query("UPDATE `protect` SET `counter`=0,`previousCon`=now() WHERE `ip` LIKE '$ip' LIMIT 1");
        exit();
    }else if($timeSpan<=10){
        $counter++;
        if($counter>=10){
            $sql = db_query("UPDATE `protect` SET `blocked`= '1',`previousCon`=now() WHERE `ip` LIKE '$ip' LIMIT 1");
            exit();
        }else{
            $sql = db_query("UPDATE `protect` SET `counter`='$counter',`previousCon`=now() WHERE `ip` LIKE '$ip' LIMIT 1");
            exit();
        }
    }
}else{
    $sql = db_query("INSERT INTO `protect` (`ip`,`previousCon`) VALUES ('$ip',now())");
    exit();
}

Upvotes: 3

Views: 79

Answers (2)

cytsunny
cytsunny

Reputation: 5030

Not only your code doesn't work as @rlanvin mentioned, your script will eventually bring down the site even no attacker attacks your site.

Your code search the whole table twice and for a certain percentage you need to search the third time to update a record. This is bad, really bad.

As your table record every unique IP that touches your server, your table will be growing very fast. Usually searching through a table with more than 100,000 records can cause serious harm to the performance (10+ seconds to respond), depending on how much computational power your server have. However, no matter how much computational power you have, as it is an ever growing table, it will eventually reach a point where it starts to harm your server's performance badly.

At first, it maybe just making your user wait, but when it reaches a certain time (usually 30 seconds), the server will take it as error and return exceeding time limit error. So your script will bring down your site even if there are no attacker at all.

Worst still, changing / faking IP is the basic of attacker. So when there is really an attacker, very likely he will be using a large amount of IP, which make your table grow to that breaking point real fast. So even if your firewall or other lower level structure (router, for example) block the attacker some time later, instead of returning to normal, the site is still down because of your script.

So, it is recommend that you don't use the script at all.

Upvotes: 0

rlanvin
rlanvin

Reputation: 6277

Is it worth the time and computing consumption just to check it?

Absolutely not.

The final objective is to prevent robots that might cause some damage to my website (some script that could damage my databases if I coded something wrong and didn't realise), but will the robots change ips each time they connect to somewhere so this code will do nothing?

There are different questions here.

  • if your script could "damage the databases", only one query can do the damage. Preventing repeated queries will not do anything. You need to fix your code. (Side note: as I'm sure you know, a script that modifies the database should be called with HTTP POST, and - in most situations - with a CSRF token. This help prevent some accidental damages.)
  • legitimate robots (such as indexers) usually use the same IPs, but usually they also to play nice and don't spam your website with hundreds of request per seconds (usually), so they should not be a problem to you. Botnets on the other do change IP addresses, so yeah... your code is useless.

Did you think of all the legitimate cases where many requests can come from the same IP address?

  • A single user opening many tabs at once for example. Will you ban the user for that?
  • Many users behind a proxy/NAT connection, such as a household, a public wifi, or a company network. They all go to your website, open a couple of tab... and get banned?

I was thinking about adding this code at the beginning of every raw php page, I mean the ones that just make changes in the server site... so maybe I can reduce the span and counter?

Seriously, don't do that.

You have one very specific use cases where throttling is useful: to prevent brute-forcing of passwords (typically in a login form). You don't do that by IP address only though (as we saw, it's mostly useless) but instead by user account. Too many failed attempt on one account? This account is locked for a few minutes.

Now if you have a specific IP address that is spamming your website, then banning it with a firewall or the web server directly is going to be much, much more efficient.

Upvotes: 4

Related Questions