What is the best method to prevent a brute force attack?

lecardo picture lecardo · Apr 3, 2013 · Viewed 37.7k times · Source

I have my login page and of course I want to prevent brute force attacks and cause less delay for the users when they are logging in.

Currently, you type in your username and password to log in.

I am considering implementing a reCAPTCHA. However, this shows on login after 3 failed attempts.

My question is:

  1. What do you base the attempt on. IP addresses? It can always be hidden... username? What if they're trying a user that doesn't exist?

  2. What would be the best method to count the failed login attempts?

Answer

Sammitch picture Sammitch · Apr 4, 2013

Sessions are unreliable because they rely on cookies, CAPTCHAs are regularly broken [including ReCAPTCHA]. The only reliable method is deceptively simple: ask a question. Don't use a math question because computers are surprisingly adept at solving those for some reason. Great old standbys are things like:

  • What is the fourth word in the sixth paragraph on this page?
  • What is the name of the author of this site? [hint]

This is stupid-easy to implement, and very difficult for a machine to solve.

As for bute-forcing, try adding two fields to your user table, 'first_failed_login' [INTEGER unix timestamp or DATETIME] and 'failed_login_count'. [INTEGER]

<?php
$bad_login_limit = 3;
$lockout_time = 600;

$first_failed_login, failed_login_count; // retrieve from DB

if(
    ($failed_login_count >= $bad_login_limit)
    &&
    (time() - $first_failed_login < $lockout_time)
) {
  echo "You are currently locked out.";
  exit; // or return, or whatever.
} else if( /* login is invalid */ ) {
  if( time() - $first_failed_login > $lockout_time ) {
    // first unsuccessful login since $lockout_time on the last one expired
    $first_failed_login = time(); // commit to DB
    $failed_login_count = 1; // commit to db
  } else {
    $failed_login_count++; // commit to db.
  }
  exit; // or return, or whatever.
} else {
  // user is not currently locked out, and the login is valid.
  // do stuff
}

This will make your login system recognize only 3 login attempts per user every 10 minutes.