How to delay login attempts after too many tries (PHP)

落爺英雄遲暮 提交于 2019-12-03 06:22:33

问题


I'm working on a fairly large web site built in PHP that will potentially have a lot of users. I'm looking into a way to protect the login screen from automated attempts. I have already included a CAPTCHA check on the registration form, yet want to harden the site more.

There have been similar questions on StackOverflow that I know of, and I know I'm capable of implementing this myself from scratch (storing login attempts and their time in the db), yet I dislike that path:

  • Conceptually, I think this kind of logic belongs at the web server/infrastructure level, not the application level. I dislike having this logic and complexity in my application
  • I worry about performance, particularly at the database level.
  • I'm lazy, in a good way, by not wanting to build a common utility like this from scratch

Any advise is appreciated, I think that I'm particularly looking for some kind of Apache module that can do this. My platform is PHP5 (using CodeIgniter), Apache2, MySQL 5.


回答1:


update: do not use sleep() for rate limiting! this doesn't make sense at all. i don't have a better solution on hand.


a good start would be to just sleep(1); after a failed login attempt - easy to implement, almost bug-free.

1 second isn't much for a human (especially because login attempts by humans don't fail to often), but 1sec/try brute-force ... sloooow! dictionary attacks may be another problem, but it's in the same domain.

if the attacker starts too may connections to circumvent this, you deal with a kind of DOS-attack. problem solved (but now you've got another problem).

some stuff you should consider:

  • if you lock accounts soley on a per IP basis, there may be problems with private networks.
  • if you lock accounts soley on a username basis, denial-of-service attacks agains known usernames would be possible
  • locking on a IP/username basis (where username is the one attacked) could work better

my suggestion: complete locking is not desireable (DOS), so a better alternative would be: count the login attempts for a certain username from a unique IP. you could do this with a simple table failed_logins: IP/username/failed_attempts

if the login fails, wait(failed_attempts); seconds. every xx minutes, run a cron script that decreases failed_logins:failed_attempts by one.

sorry, i can't provide a premade solution, but this should be trivial to implement.

okay, okay. here's the pseudocode:

<?php
$login_success = tryToLogIn($username, $password);

if (!$login_success) {
    // some kind of unique hash
    $ipusr = getUserIP() . $username;

    DB:update('INSERT INTO failed_logins (ip_usr, failed_attempts) VALUES (:ipusr, 1) ON DUPLICATE KEY UPDATE failed_logins SET failed_attempts = failed_attempts+1 WHERE ip_usr=:ipusr', array((':ipusr' => $ipusr));

    $failed_attempts = DB:selectCell('SELECT failed_attempts WHERE ip_usr=:ipusr', array(':ipusr' => $ipusr));

    sleep($failed_attempts);
    redirect('/login', array('errorMessage' => 'login-fail! ur doin it rong!'));
}
?>

disclaimer: this may not work in certain regions. last thing i heard was that in asia there's a whole country NATed (also, they all know kung-fu).




回答2:


A very dummy untested example, but I think, you will find here the main idea ).

if ($unlockTime && (time() > $unlockTime))
{
    query("UPDATE users SET login_attempts = 0, unlocktime = 0 ... ");
}
else
{
   die ('Your account is temporary locked. Reason: too much wrong login attempts.');
}
if (!$logged_in)
{
    $loginAttempts++;
    $unlocktime = 0;
    if ($loginAttempts > MAX_LOGIN_ATTEMPTS) 
    {
        $unlockTime = time() + LOCK_TIMEOUT;
    }
    query("UPDATE users SET login_attempts = $loginAttempts, unlocktime = $unlocktime ... ");
}

Sorry for the mistakes - I wrote it in some seconds ad didn't test... The same you can do by IP, by nickname, by session_id etc...




回答3:


Why don't you wait with "hardening" and "scaling" your app until you actually have that problem? Most likely scenario is that the app will never have "a lot of users". This sounds like premature optimization to me, something to avoid.

  • Once you get bots abusing, harden the signup. I'd actually remove the captcha until you start getting > 1000 signups/day.
  • Once you get performance problems, improve performance by fixing real bottlenecks.


来源:https://stackoverflow.com/questions/886665/how-to-delay-login-attempts-after-too-many-tries-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!