phpsecuritythrottlingip-blocking

Login Throttling and blocking all IP addresses


I must throttle the login and I want to block all the IPs if a large scale failed attempts is coming in. How can I achieve that using the below code? If the below code is not good enough, please inform of a good tutorial on this matter.

<?php
$throttle = array(1 => 1, 10 => 2, 1000 => 'captcha');
$getfailedq = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$getfailed = $muc->prepare($getfailedq);
$getfailed->execute();
if ($getfailed->rowCount() > 0) {
    $row = $getfailed->fetch(PDO::FETCH_ASSOC);
    $latest_attempt = (int) date('U', strtotime($row['attempted']));
    $getfailedq = 'SELECT Count(*) AS failed FROM failed_logins WHERE attempted > Date_sub(Now(), INTERVAL 15 minute)';
    $getfailed = $muc->prepare($getfailedq);
    $getfailed->execute();
    if ($getfailed->rowCount() > 0) {
        $row = $getfailed->fetch(PDO::FETCH_ASSOC);
        $failed_attempts = (int) $row['failed'];
        krsort($throttle);
        foreach ($throttle as $attempts => $delay) {
            if ($failed_attempts > $attempts) {
                if (is_numeric($delay)) {
                    $remaining_delay =  time() - $latest_attempt + $delay;
                    echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
                } else {
                    echo "captcha";
                }
                break;
            }
        }        
    }
}
?>

Solution

  • This is mostly pseudo code, based on your example. You could add an ip field to your failed_logins table, along with creating a new table named blocked_logins.

    <?php
    
    // get users IP address
    $ip = $_SERVER['REMOTE_ADDR'];
    
    // find out if user has already been blocked
    $getblockedq = 'SELECT ip FROM blocked_logins WHERE ip = :ip';
    $getblocked = $muc->prepare($getblockedq);
    $getblocked->execute(array(':ip' => $ip));
    $total = $getblocked->fetchColumn();
    
    if ($total > 0) {
        // user is blocked, do not proceed
    }
    
    // find number of failed logins within past 15 mins
    $getfailedq = 'SELECT Count(*) AS failed FROM failed_logins WHERE ip = :ip AND attempted > Date_sub(Now(), INTERVAL 15 minute)';
    $getfailed = $muc->prepare($getfailedq);
    $getfailed->execute(array(':ip' => $ip));
    $total = $getfailed->fetchColumn();
    
    if ($total <= 2) {
        // looks good, attempt to login
    } elseif ($total <= 10) {
        // you must wait x seconds...
    } elseif ($total <= 1000) {
        // display captcha
    } else {
        // block user
    }
    

    This should at least get you started in the right direction.