Throttle User Login Attempts in PHP

The Problem: Brute Force Attack

If you have ever ran a successful user based website where users have Accounts with a username and password, you may have been the target of a Brute Force Attack. Where some one, usually with the aide of a bot tries to crack user passwords and gain access to there account.

Preventing large numbers of rapid-fire successive login attempts (ie. the brute force attack) really isnt that difficult. But preventing it right isnt as easy as it seems.

The Solution: 3 Choices effective against brute-force attacks

  • Present a CAPTCHA after X amount of failed login attempts (annoying as hell and sometimes ineffective as Captcha cracking technology has advanced so much in the past few years)
  • Locking accounts and requiring email verification after X amount of failed login attempts (this is a DoS attack waiting to happen)
  • Login Throttling: Setting a time delay between attempts after X failed login attempts (DoS attacks are still possible, but at least they are far less likely and a lot more complicated to pull off).

Login Throttling Method

I believe Login Throttling is the best solution, below is a simple example in PHP of how you might implement it into a user login system by storing the Failed login attempts to a MySQL Database.

The idea is simple, you cannot simply prevent rapid-fire login attempts by throttling down based on a single IP or username as the attacker can use multiple IPs and multiple user accounts as a way of bypassing your throttling efforts.

Instead, you should be tracking all failed login attempts across the site and associating them to a timeframe instead of an IP or account.

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 have trouble remembering their password.

So we create a MySQL table named failed_logins to store the failed login attempts

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 below

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

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 until the number of failed attempts over the given time period is less than the threshold.

Using Captcha 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.

This is more of a technique than a drop in code. You can take this code and expand/modify it to meet the needs of your system.

* Portions of the code in this article are credited to Corey Ballou aka cballou on StackOverflow