What is the best Distributed Brute Force countermeasure?

前端 未结 16 1896
逝去的感伤
逝去的感伤 2020-11-28 16:55

First, a little background: It is no secret that I am implementing an auth+auth system for CodeIgniter, and so far I\'m winning (so to speak). But I\'ve run into a pretty no

16条回答
  •  生来不讨喜
    2020-11-28 17:31

    I had previously answered a very similar question over at How can I throttle user login attempts in PHP. I'll reiterate the proposed solution here as I believe many of you will find it informational and useful to see some actual code. Please bare in mind that using a CAPTCHA might not be the best solution due to the increasingly accurate algorithms being used in CAPTCHA busters nowadays:

    You cannot simply prevent DoS attacks by chaining throttling down to a single IP or username. Hell, you can't even really prevent rapid-fire login attempts using this method.

    Why? Because the attack can span multiple IPs and user accounts for the sake of bypassing your throttling attempts.

    I have seen posted elsewhere that ideally you should be tracking all failed login attempts across the site and associating them to a timestamp, perhaps:

    CREATE TABLE failed_logins(
        id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        username VARCHAR(16) NOT NULL,
        ip_address INT(11) UNSIGNED NOT NULL,
        attempted DATETIME NOT NULL
    ) engine=InnoDB charset=UTF8;
    

    Decide on certain delays based on the overall number of failed logins in a given amount of time. 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 can recall (and type) their password.


    10 failed attempts = 1 second
    20 failed attempts = 2 seconds
    30 failed attempts = reCaptcha
    

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


    SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);
    

    If the number of attempts over the given period of time is over your limit, either enforce throttling or force all user's to use a captcha (i.e. reCaptcha) until the number of failed attempts over the given time period is less than the threshold.

    // array of throttling
    $throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');
    
    // assume query result of $sql is stored in $row
    $sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
    $latest_attempt = (int) date('U', strtotime($row['attempted']));
    // get the number of failed attempts
    $sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';
    // assume the number of failed attempts was stored in $failed_attempts
    krsort($throttle);
    foreach ($throttle as $attempts => $delay) {
        if ($failed_attempts > $attempts) {
            // we need to throttle based on delay
            if (is_numeric($delay)) {
                $remaining_delay = time() - $latest_attempt - $delay;
                // output remaining delay
                echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
            } else {
                // code to display recaptcha on login form goes here
            }
            break;
        }
    }
    

    Using reCaptcha at a certain threshold would ensure that an attack from multiple fronts would be minimized and normal site users would not experience a significant delay for legitimate failed login attempts. I can't gaurantee prevention, as it's already been expanded upon that CAPTCHA's can be busted. There are alternative solutions, perhaps a variant of "Name this animal", which could work quite well as a substitute.

提交回复
热议问题