Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I throttle user login attempts in PHP

I was just reading this post The definitive guide to form-based website authentication on Preventing Rapid-Fire Login Attempts.

Best practice #1: A short time delay that increases with the number of failed attempts, like:

1 failed attempt = no delay
2 failed attempts = 2 sec delay
3 failed attempts = 4 sec delay
4 failed attempts = 8 sec delay
5 failed attempts = 16 sec delay
etc.

DoS attacking this scheme would be very impractical, but on the other hand, potentially devastating, since the delay increases exponentially.

I am curious how I could implement something like this for my login system in PHP?

like image 878
JasonDavis Avatar asked Jan 19 '10 03:01

JasonDavis


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 (!

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.


2 Answers

You have three basic approaches: store session information, store cookie information or store IP information.

If you use session information the end user (attacker) could forcibly invoke new sessions, bypass your tactic, and then login again with no delay. Sessions are pretty simple to implement, simply store the last known login time of the user in a session variable, match it against the current time, and make sure the delay has been long enough.

If you use cookies, the attacker can simply reject the cookies, all in all, this really isn't something viable.

If you track IP addresses you'll need to store login attempts from an IP address somehow, preferably in a database. When a user attempts to log on, simply update your recorded list of IPs. You should purge this table at a reasonable interval, dumping IP addresses that haven't been active in some time. The pitfall (there's always a pitfall), is that some users may end up sharing an IP address, and in boundary conditions your delays may affect users inadvertantly. Since you're tracking failed logins, and only failed logins, this shouldn't cause too much pain.

like image 34
Mark Elliot Avatar answered Sep 22 '22 04:09

Mark Elliot


You cannot simply prevent DoS attacks by chaining throttling down to a single IP or username. You can't even really prevent rapid-fire login attempts using this method.

Why? Because the attack can span multiple IPs and user accounts for the sake of bypassing your throttling attempts.

I have seen posted elsewhere that ideally you should be tracking all failed login attempts across the site and associating them to a timestamp, perhaps:

CREATE TABLE failed_logins (     id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,     username VARCHAR(16) NOT NULL,     ip_address INT(11) UNSIGNED NOT NULL,     attempted DATETIME NOT NULL,     INDEX `attempted_idx` (`attempted`) ) engine=InnoDB charset=UTF8; 

A quick note on the ip_address field: You can store the data and retrieve the data, respectively, with INET_ATON() and INET_NTOA() which essentially equate to converting an ip address to and from an unsigned integer.

# example of insertion INSERT INTO failed_logins SET username = 'example', ip_address = INET_ATON('192.168.0.1'), attempted = CURRENT_TIMESTAMP; # example of selection SELECT id, username, INET_NTOA(ip_address) AS ip_address, attempted; 

Decide on certain delay thresholds based on the overall number of failed logins in a given amount of time (15 minutes in this example). You should base this on statistical data pulled from your failed_logins table as it will change over time based on the number of users and how many of them can recall (and type) their password.


> 10 failed attempts = 1 second > 20 failed attempts = 2 seconds > 30 failed attempts = reCaptcha 

Query the table on every failed login attempt to find the number of failed logins for a given period of time, say 15 minutes:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute); 

If the number of attempts over the given period of time is over your limit, either enforce throttling or force all users to use a captcha (i.e. reCaptcha) until the number of failed attempts over the given time period is less than the threshold.

// array of throttling $throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');  // retrieve the latest failed login attempts $sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins'; $result = mysql_query($sql); if (mysql_affected_rows($result) > 0) {     $row = mysql_fetch_assoc($result);      $latest_attempt = (int) date('U', strtotime($row['attempted']));      // get the number of failed attempts     $sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';     $result = mysql_query($sql);     if (mysql_affected_rows($result) > 0) {         // get the returned row         $row = mysql_fetch_assoc($result);         $failed_attempts = (int) $row['failed'];          // assume the number of failed attempts was stored in $failed_attempts         krsort($throttle);         foreach ($throttle as $attempts => $delay) {             if ($failed_attempts > $attempts) {                 // we need to throttle based on delay                 if (is_numeric($delay)) {                     $remaining_delay = time() - $latest_attempt - $delay;                     // output remaining delay                     echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';                 } else {                     // code to display recaptcha on login form goes here                 }                 break;             }         }             } } 

Using reCaptcha at a certain threshold would ensure that an attack from multiple fronts would be stopped and normal site users would not experience a significant delay for legitimate failed login attempts.

like image 152
Corey Ballou Avatar answered Sep 22 '22 04:09

Corey Ballou



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!