Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throttle login attempts - PHP & MySQL & CodeIgniter

I'd like to be able to throttle login attempts based on failed attempts but I got some questions.

Should I use MySQL? (read that it could strain the DB)
Should I throttle per user and system-wide or just system-wide? (so to stop normal people from guessing passwords)
How should I calculate my threshold? (so it automatically adapts to changes/growth)
How should I retrieve this threshold? Query/calculate on every fail or store on cache?
What should I use to throttle? (read a response that sleep() could end up straining the server)

Does anybody have some sample code?

I'm quite new at this so I appreciate the help! Thanks

like image 386
RS7 Avatar asked Feb 18 '11 02:02

RS7


People also ask

How do I limit the number of login attempts in PHP?

php function init() { //$showInsertDat = insert login name from your login form $attempts = passwordattempt($showInsertDat); $tries = $_SESSION['login_attempts'] = $attempts; echo "Versuch: " . $tries; } function passwordattempt($insertLoginName) { session_start(); $i = 0; //if session is not set if (!

How do you implement limit login attempts?

Use some columns in your users table 'failed_login_attempts' and 'failed_login_time'. The first one increments per failed login, and resets on successful login. The second one allows you to compare the current time with the last failed time.

What is throttling of login attempts?

One of the best countermeasures to these attacks is called "login throttling", which denies a user from attempting logins after a certain number of failed attempts.

How do I monitor failed login attempts?

Open Event Viewer in Active Directory and navigate to Windows Logs> Security. The pane in the center lists all the events that have been setup for auditing. You will have to go through events registered to look for failed logon attempts.


1 Answers

I implemented a poor-man's throttling mechanism in phunction using APC alone, this is how I use it:

// allow 60 requests every 30 seconds
// each request counts as 1 (expensive operations can use higher values)
// keep track of IPs by REMOTE_ADDR (ignore others)

$throttle = ph()->Throttle($ttl = 30, $exit = 60, $count = 1, $proxy = false);

if ($throttle === true)
{
    // IP exceded 30 requests in the last 60 seconds, die() here
}

else
{
    // $throttle is a float
    // number of requests in the last 30 seconds / 30 seconds

    /*
     1 req / 30 = 0,033 sec
     5 req / 30 = 0,166 sec
    10 req / 30 = 0,333 sec
    15 req / 30 = 0,5   sec
    20 req / 30 = 0,666 sec
    25 req / 30 = 0,833 sec
    30 req / 30 = 1     sec
    */

    usleep(intval(floatval($throttle) * 1000000));
}

I use this on my Front-Controller and pass the value to my routing method, but that's another story.

The bottom line is that if you use APC you're able to keep things very fast in memory and with little memory consumption because APC follows a FILO methodology. If you need way higher timeouts you may consider using something that's not memory based though.

BTW: MySQL supports tables with the MEMORY engine.


The problem with sleep():

A typical Apache web server with PHP installed as a module will eat about 10 MB of RAM per instance, to avoid exceeding your available ram there are some Apache settings that you can configure to limit the maximum number of instances that Apache is able to start.

The problem is when you sleep(), that instance is still active and with enough requests could end up eating all the available slots to start new servers, thus rendering your web site inaccessible until some pending requests are completed.

There is no way to overcome this from PHP AFAIK, so in the end it's up to you.


The principle is the same for system wide throttling:

function systemWide($ttl = 86400, $exit = 360)
{
    if (extension_loaded('apc') === true)
    {
        $key = array(__FUNCTION__);

        if (apc_exists(__FUNCTION__) !== true)
        {
            apc_store(__FUNCTION__, 0, $ttl);
        }

        $result = apc_inc(__FUNCTION__, 1);

        if ($result < $exit)
        {
            return ($result / $ttl);
        }

        return true;
    }

    return false;
}
like image 116
Alix Axel Avatar answered Sep 29 '22 23:09

Alix Axel