Hello all!

I wanted to ask everyone what they thought about the sleep function in php. I do believe I'm going to use it for my website, but I'm really unsure how to implement it in. I wanted to use it on the login page. I googled this until I'm blue in the face and can't get anywhere. Does anyone know of a good site that shows lots of examples? Or can someone show me where to put it in a login code?

Thanks bunches!
~Amy

Hello all!

I wanted to ask everyone what they thought about the sleep function in php. I do believe I'm going to use it for my website, but I'm really unsure how to implement it in. I wanted to use it on the login page. I googled this until I'm blue in the face and can't get anywhere. Does anyone know of a good site that shows lots of examples? Or can someone show me where to put it in a login code?

Thanks bunches!
~Amy

I've never used the sleep function. I think its usefulness is limited to very few things. Can you be more specific about what you are going to use it for?

Like I said, I want to use it for the LogIn page, so if hackers want to try to use 50 billion passwords to find the right username, or vice versa, it may take them longer than they want to wait.

Since you don't use the sleep function, I'm curious to know what you use for security. I've heard both good and bad things about the sleep function. I don't think it will hurt to use it and any additional security to try to prevent the wrong ones from entering.

~Amy

Like I said, I want to use it for the LogIn page, so if hackers want to try to use 50 billion passwords to find the right username, or vice versa, it may take them longer than they want to wait.

Since you don't use the sleep function, I'm curious to know what you use for security. I've heard both good and bad things about the sleep function. I don't think it will hurt to use it and any additional security to try to prevent the wrong ones from entering.

~Amy

I limit the number of failed attempts for that user, then lock the account, then unlock it after an hour once the activity stops or at password reset, which ever comes first.

Hmmm...that sounds like a good idea. But what about if a hacker has a password and then does nothing but try to figure out what the username is. How do you prevent those attacks?

~Amy

Hmmm...that sounds like a good idea. But what about if a hacker has a password and then does nothing but try to figure out what the username is. How do you prevent those attacks?

~Amy

WOW, you are thorough. Guess I never really considered that. I'm still not convinced that it is the best way to handle it since it would effect the other legitimate users as well though. But if you want to, I think it should be right before the database connection.

Yes, but I think if it were only delayed a few seconds I don't think that most users would have a major problem with it.

I guess it could be possible to do both? Limit the # of attempts as well as using the sleep function?

~Amy

Once again, hackers might keep trying the passwords, but you might want to try an approach of blocking ip's. 5 attempts at an ip with an incorrect password, record the ip in a table, and pull back from the table when user's are accessing the login page. If they match an ip in the table, disable the ability to log in or along those lines. Yes they can spoof the ip's, but it is a viable solution.

That sounds like a pretty good idea...of course they could go to any computer, but it would make it harder for them.

I am not sure exactly how to write all that php code. Can you point me into the right direction, a website perhaps, that discusess this?

I really appreciate it :)

~Amy

Here's a link of how to get the ip address
http://www.plus2net.com/php_tutorial/php_ip.php

Then just set up table along the lines of

BLOCKED_IP
FAILED_LOGIN_ATTEMPTS
LAST_FAILED_TIME

When the user accesses the page, check the ip against blocked_ip, if it matches then check LAST_FAILED_TIME and FAILED_LOGIN_ATTEMPTS, if it is greater than 30 min and whatever value for FAILED_LOGIN_ATTEMPTS you choose, then display the login page, otherwise dispaly the access denied page and increment the FAILED_LOGIN_ATTEMPTS. If you allow access, delete the row for that ip. If the user types in a bad password insert or increment the FAILED_LOGIN_ATTEMPTS.

You might want to go about it a little different of a way, but there is a good start.

Thanks

I'm trying to locate my php.ini file so I can see if the register_global are off. If it is on, is it enough to just use the $ip=@$REMOTE_ADDR; or am I still going to have to use the code if they are behind a proxy?

I'm trying to get a feel for how all of this works :)
~Amy

The problem will be that if your users are behind the proxy, you will be blocking all of them from the same ip address without using the additional code.
If they aren't behind the proxy REMOTE_ADDR will work, otherwise you will be blocking the whole proxy for a client address inside of that proxy.

Okay, so regardless if I use the $ip=@$REMOTE_ADDR; or the $ip=$_SERVER; I should still use something to check to see if they are behind the proxy, is that right?
~Amy

It's good to be thorough ... I was thinking "Why just test failed passwords", why not limit failed login attempts in general.

Also, any respectable hacker will use an automated script to do a brute force attack (like what you're worried about), and maybe an onion router to hide their IP address.

Cookie values aren't safe either ... hmmn?

What do you folks think...would this be a good method to protect from multiple login attempts?

The only thing I see possibly wrong with it, is if multiple users have the same username or the same password as other users. Plus this requires NOT using the forward-slash '/' or back-slash '\' characters in the username and password.

<?php

// CONFIGURATION VALUES -- register_globals must be OFF 
$max_attempts = 5;   // no more than this many login attempts
$time_seconds = 300; // within this time-frame, in seconds
$temp_path = 'temp'; // no trailing forward-slash '/'

login_attempt();

function login_attempt () {
  global $max_attempts, $time_seconds, $temp_path;
  if ( $_REQUEST['username'] && $_REQUEST['password'] ) {
    $username = trim( $_REQUEST['username'] );
    $password = trim( $_REQUEST['password'] );
    // forbidden username or password characters: / \
    $user = preg_replace( '#/#', '', stripslashes( $username ) );
    $pass = preg_replace( '#/#', '', stripslashes( $password ) );
    $tpath = make_directory( $temp_path );
    $user_temp = $tpath."UN_$user.tmp";
    $pass_temp = $tpath."PW_$pass.tmp";
    $allow_user = test_attempts( $user_temp, $max_attempts, $time_seconds );
    $allow_pass = test_attempts( $pass_temp, $max_attempts, $time_seconds );
    if ( $allow_user && $allow_pass ) {
      print 'PROCEED';
      // We're okay to process the username and password for login ...
      // get database username and password, and compare Md5( $pass )
    } else {
      // do something more elegant here
      die( "Too many login attempts under user name or password<br>Please wait a bit" );
    }
  } else {
    // do something more elegant here
    die( "Please enter your user name and password" );
  }
  handle_garbage( $tpath, $time_seconds, 'tmp' );
}

function test_attempts ( $file, $max, $life ) {
  $allow = FALSE;
  $record = array();
  if ( is_file( $file ) ) {
    $count = 0;
    $now = time();
    $attempts = file( $file );
    foreach ( $attempts as $attempt ) {
      $time = trim( $attempt );
      if ( $now - $time < $life ) {
        $record[] = $time;
        $count ++;
      }
    }
    if ( $count < $max ) {
      $record[] = $now;
      $allow = TRUE;
    }
    file_put_contents( $file, implode( "\n", $record ) );
  } else {
    file_put_contents( $file, time() );
    $allow = TRUE; 
  }
  return $allow;
}

function make_directory ( $path ) {
  $exists = FALSE;
  if ( !$exists = is_dir( $path ) ) {
    $exists = mkdir( $path, 0777, TRUE );
  }
  return ( $exists ) ? rtrim($path,'/').'/' : '.';
}
  
function handle_garbage ( $path, $life, $ext ) {
  //$life => minimum lifetime for temp files in seconds 
  if ( $dir = opendir( $path ) ) {
    while ( ( $file = readdir( $dir ) ) !== FALSE ) {
      $file = $path.$file;
      if ( is_file( $file ) && strpos( $file, ".$ext" ) > 0 ) {
        if ( time() > ( filemtime( $file ) + $life ) ) {
          @unlink( $file );
        }
      }
    }
    closedir( $dir );
  }
}
?>

Cheers

Okay, so if I block the IP addresses, it's possible the hacker will have an onion router so I can't see their IP address.

If I use something to shut down the user themselves and not let them get into their account after so many wrong attempts, I may have a lot of users try to get in touch with me with complaints.

I'm understanding that there are even problems with the sleep function.

If we use all these functions at once, are we really any safer? Can we win?

~Amy

It is a constant battle to keep up with security and hackers or what not.

The only thing you can do is try and stay ahead of the game.
Make users have secure passwords, if user's are complaining, make them do a captcha with email address or something along those lines. Make sure your database is secure, as far as accessibility from external ips and users. Make sure you don't directly take user input and try to issue a database command with it. Althought it may take a little more time to implement and code these strategies, it will deter many hacking attempts to begin with.

Hi Amy,

Okay, so if I block the IP addresses, it's possible the hacker will have an onion router so I can't see their IP address.

I don't fully understand onion routers, but if I understand correctly -- users within a group share, or mix and match IP addresses in order to make back-tracing to one specifiic user impossible. This might be used for hacking attempts, and add more IPs to the mix of ones detected...but don't quote me on that.

If I use something to shut down the user themselves and not let them get into their account after so many wrong attempts, I may have a lot of users try to get in touch with me with complaints.

I've forgotten my password before and been max-attempted out of trying to login to a site. The user will know they are pushing the envelope. You can also include a way for a user to reset their password to their database-stored email address (only). You shouldn't get too many complaints when the users realize their personal info is safe with you. Also, my little script resets after the time-limit -- on every attempt, not as a batch.

I'm understanding that there are even problems with the sleep function.

If we use all these functions at once, are we really any safer? Can we win?

I'm not sure I would use sleep, it freezes the whole script execution and probably will frustrate users. My little example takes number of attempts within a specific time-frame into consideration without using sleep.

As was mentioned, there is no absolute security methodology. There is only your best effort against the hackers. Also, how sensitive is your data that you're protecting -- how tempting is it to advanced hackers? If it is really valuable, I would recommend getting a security specialist on-board, otherwise do your best and get a good nights sleep.

Cheers

To tell you the truth, there is nothing really valuable. What I mean is that pretty much everything that they type into their account gets posted online, except for some small things. They know this in advance. I do not have any credit card info or SS#'s or anything of the such. But my customers are allowed to upload pics and I would just like things to remain clean. I'd hate to get on there one day and see some dirty pics of a blonde doing a midget or something. It just wouldn't be very appropriate, ya know?

I really appreciate everyone writing in, this is a great response! Now if I can just figure out which one would be best...I think I'm leaning toward allowing the user to only have a certain amount of attempts. Is it possible and do you think it would be a good idea to let the user know after each attempt that they only have a certain number of attempts left?

~Amy

Its all up to you. Typically you would not let the user know how many attempts they have left and just display a message after they have locked themselves out, that their account has been locked and will be available in 'x minutes' or if they reset their password or whatever method you choose.

Another reason that you wouldn't let them know, is if you ever decide to change the number of attempts, you might have to change the error message. Also with the hacking thing, this will let them know how many chances they have left to try for this account, before moving on to the next one.

All in all, still a personal preference.

dickersonka makes good points, especially about alerting hackers to how many attempts they have. It would be easy enough to calculate how many attempts within a certain period the hacker has and write a delay in their script to compensate for that.

Of course, 5 attempts every 5 minutes (how it is set now) would only allow 60 possible usename-password combinations an hour, which would take a decade to perform a brute force attack if the password is at all secure.

If you want to show number of attempts, you can do so dynamically by returning the count from the test_attempts function: replace return $allow; with...

return ( $allow ) ? $count : FALSE;

...and in your main function after print 'PROCEED'; when you've tested if the username and password match the database-stored values ... if they don't you can display the greater of the current counts...

print ( $allow_user > $allow_pass ) ? $allow_user : $allow_pass;

I didn't test the above snippets, but they should work

Hope this helps

Okay, still haven't tested it but realized a fatal flaw in my logic above...NOT
return ( $allow ) ? $count : FALSE;

For count up

return ( $allow ) ? $count +1 : FALSE;

For count down

return ( $allow ) ? $max - ($count + 1) : FALSE;

Or something like this...you might have to play with it some...you just don't want to return a zero (0) count, as that will be interpreted as FALSE. :-)

Cheers

You know, you can implement a system to beat that situation where a hacker is using a specific password with several usernames by just blocking any attempt on that password for the next hour or so. I would create an abuse table or set of tables and abused passwords would be one of them with password, timestamp and attempts as the columns. Just keep it cleaned up with cron.

So there is a way to limit failed login attempts that are either for wrong passwords or for wrong usernames?

Langsor, have you tested the php you posted earlier?

Thanks,
~Amy

So there is a way to limit failed login attempts that are either for wrong passwords or for wrong usernames?

Langsor, have you tested the php you posted earlier?

Thanks,
~Amy

Yes I did test the main block after I wrote it, but not in a production environment, so I can not guarantee this in any way without further testing and you will have to rely on your own judgment if you want to use it.

I did not actually test the small additional pieces in my last couple posts though, those were off the top of my head.

Let me know if you have any questions or need any help with this code.

So there is a way to limit failed login attempts that are either for wrong passwords or for wrong usernames?

Langsor, have you tested the php you posted earlier?

Thanks,
~Amy

Everything has a solution, you just have to be creative.

Okay, I'm come up with something else, please tell me if you think it would be a good idea or not.

My website is a site where you can go in and post your home online by county. Is it possible to prevent some attacks by making the user put in not only their username and password, but also the county in which they live? I could write the php code to check all of that and if they got it all correct, then they are smooth sailing.

The only problem I worried about running into would be if they didn't spell their county correctly, but I think it would take a real moron to not know how to spell their own county, but then again, I have to expect that, I suppose. Hehe

Since their are over 3,000 counties, do you believe this is a good idea for prevention?

~Amy

This article has been dead for over six months. Start a new discussion instead.