Welcome Guest, Not a member yet? Register   Sign In
Authentication and Blocking Login Attempts after 'n' tries
#1

[eluser]Glazz[/eluser]
Hey there,

I've created a basic authentication library, based on ion auth, it is more cleaner ( at least for me )..

And i added a feature to block a user after 'n' failed logins for let's say 30 minutes.

It is working fine, but i don't know if this is the best way to do this.

I was using sessions to store the ammount of failed login attempts, but then i switched to database.

Here are the code that i'm using:
http://pastebin.com/AWN72s4q

Here are the full code of the library:
http://pastebin.com/GciLbcNn

How it is working:

When a user press the login button if the login fails it calls the loginAttempt() function
If the user do this 3 times the next time he tries to login he gets blocked because the function isBlocked() is being called on the very top of the login() function.

My question is, do you think this is "effective" ? Or do you suggest something else ?

Thanks !
#2

[eluser]Aken[/eluser]
That's about how I would do it. Store the number of attempts by IP. Once it hits a number, block them for a certain number of time.

Might be able to save some processing by storing a "blocked_until" column with a timestamp whenever the limit has been reached (done somewhere else rather than the isBlocked() method). Then the isBlocked method just checks if that date exists and compares to the current time if so. Essentially it's the same thing, just done a little differently.
#3

[eluser]Glazz[/eluser]
Hi Aken,

Yeap that's how it is working:

Code:
// Check if we have the user record.
  //
  $record = $this->CI->db->where('ip_address', $ip_address)->get('login_attempts')->row();
  if ( ! empty( $record ) ):
   // Check this user login attempts.
   //
   if ( $record->attempts >= 3 ):
    // Check if the user block has expired.
    //
    if( ( time() - $record->lastLogin ) > $blockTime ):
     // Clear this user loginAttempts.
     //
     $this->CI->db->where('ip_address', $ip_address)->update('login_attempts', array( 'attempts' => 0, 'lastLogin' => time() ) );

     // User is not blocked anymore.
     //
     return false;
    else:
     // The user is blocked.
     //
     return true;
    endif;
   endif;
  endif;

The $record->lastLogin records the time the user tried to login but failed, it updates everytime the user fails a login, so when he reaches 3 times, and get blocked, i use that to see if the block time has expired.
#4

[eluser]PhilTem[/eluser]
I'd probably lock the user out by both the IP as well as the provided username since an IP can be changed easily within seconds and then your library is, sorry to say, useless Wink
Or just log the username and lock it out for 1h after 3 failed attempts.
#5

[eluser]Glazz[/eluser]
[quote author="PhilTem" date="1336520709"]I'd probably lock the user out by both the IP as well as the provided username since an IP can be changed easily within seconds and then your library is, sorry to say, useless Wink
Or just log the username and lock it out for 1h after 3 failed attempts.[/quote]

Good point thanks !

Maybe i lock the account the user is trying to login with ( if the account exist of course ) and send an email to the owner of that account saying that the account was locked blah blah.. it's a good idea i guess.
#6

[eluser]InsiteFX[/eluser]
Code:
-- users table add enum field
`status` enum('active','inactive','banned','deleted') NOT NULL DEFAULT 'active',
#7

[eluser]Ayeyermaw[/eluser]
[quote author="PhilTem" date="1336520709"]I'd probably lock the user out by both the IP as well as the provided username since an IP can be changed easily within seconds and then your library is, sorry to say, useless Wink
Or just log the username and lock it out for 1h after 3 failed attempts.[/quote]

Exactly that. An additional reason to do it this way is to prevent users with the same IP address (corporate internet connections etc) don't get a blanket lockout just because one person messed up the login
#8

[eluser]Glazz[/eluser]
I've created this function:
Code:
public function bruteCheck( $failedAttempt = false, $identification = null )
{
  // Get the user ip address.
  //
  $ip_address = $this->CI->input->ip_address();

####
  $loginAttempts = 5; # save in the config file !!
  $blockTime = 1800;  # save in the config file !!
####

  // Is this a failed login attempt ?
  //
  if ( $failedAttempt ):
   // Check if we already have a record of this user.
   //
   $record = $this->CI->db->where('ip_address', $ip_address)->get('login_attempts')->row();
   if ( empty( $record ) ):
    //
    //
    $attempts = 1;

    // Create the record.
    //
    $this->CI->db->insert('login_attempts', array( 'ip_address' => $ip_address, 'attempts' => $attempts, 'lastLogin' => time() ) );

   // We do, update the record.
   //
   else:
    //
    //
    $attempts = $record->attempts + 1;

    // Update the user record.
    //
    $this->CI->db->where('ip_address', $ip_address)->update('login_attempts', array( 'attempts' => $attempts, 'lastLogin' => time() ) );
   endif;

  // This is not a failed login attempt, but we need to get the user attempts.
  //
  else:
   $record = $this->CI->db->where('ip_address', $ip_address)->get('login_attempts')->row();
   if ( empty( $record ) ):
    $attempts = 1;
   else:
    $attempts = $record->attempts + 1;
   endif;
  endif;

  // Check if the user is blocked comparing his login attempts.
  //
  if ( $attempts < $loginAttempts ):
   // User is not blocked.
   //
   $deny_login = false;

  // User is blocked now ?
  //
  else:
   // Check if the user block has expired.
   //
   if( ( time() - $record->lastLogin ) > $blockTime ):
    // User is not blocked.
    //
    $deny_login = false;

    // Clear the user record.
    //
    $this->CI->db->where('ip_address', $ip_address)->delete('login_attempts');
   else:
    // User is blocked
    //
    $deny_login = true;
   endif;
  endif;

  // Clean older login attempts, just to make the database smaller and cleaner.
  //
  # -- todo --

  // Do we want to check if the account the user is trying to login is blocked ?
  //
  if ( $identification !== null ):
   // See if we have the userID or the email.
   //
   if ( is_numeric( $identification ) ):
    $this->CI->db->where('userID', $identification);
   elseif( is_string( $identification ) ):
    $this->CI->db->where('email', $identification);
   endif;

   // Check if the account the user is trying to login is blocked.
   //
   $record = $this->CI->db->get('users')->row();
   if ( ! empty( $record ) && $record->status === 'inactive' ):
    $deny_login = true;

   // The account is not blocked.
   //
   else:
    // But do we want to block the account ?
    //
    if ( $attempts >= $loginAttempts ):
     // Block the account.
     //
     # -- todo --

     // Warn the account owner via email.
     //
     # -- todo --
    endif;
   endif;
  endif;

  // Shall we block the user login or not ?
  //
  return $deny_login;
}


It works, block by ip and checks if the account the user is trying to login with is or needs to be blocked

Example:

Code:
if ( bruteCheck( false, $email ) ):
account is blocked
else:
   do normal login but if the login fails we call bruteCheck ( true, $email )
endif;

Well it is working, do you guys suggest any other way to do this ?

I have another library, but no for this project that i want to release, that is Authentication and Authorization ( Roles and Permissions ), and i'm thinkin on implementing something like this on that library aswell..








Theme © iAndrew 2016 - Forum software by © MyBB