8.8. Throttling Failed Authentication Attempts

You want to prevent an attacker from making too many attempts at guessing a password through normal interactive means.

It's best to use a protocol where such attacks don't leak any information about a password, such as a public key-based mechanism.

Delay program execution after a failed authentication attempt. For each additional failure, increase the delay before allowing the user to make another attempt to authenticate.

Throttling failed authentication attempts is a balance between allowing legitimate users who simply mistype a password or passphrase to have a quick retry and delaying attackers who are trying to brute-force passwords or passphrases.

Our recommended strategy has three variables that control how it delays repeated authentication attempts:

The best way to institute a delay depends entirely upon the architecture of your program. If authentication is being performed over a network in a single-threaded server that is multiplexing connections with select( ) or poll( ), the best option may be to compute the future time at which the next authentication attempt will be accepted, and ignore any input until that time arrives.

When authenticating a user interactively on a terminal on Unix, the best solution is likely to be to use the sleep( ) function. On Windows, there is no strict equivalent. The Win32 API functions Sleep( ) and SleepEx( ) will both return immediately—regardless of the specified wait time—if there are no other threads of equal priority waiting to run.

In a GUI environment, any authentication dialog presented to the user will have a button labeled "OK" or some equivalent. When a delay must be made, disable the button for the duration of the delay, then enable it. On Windows, this is easily accomplished using timers.

The following function, spc_throttle( ) , computes the number of seconds to delay based on the three variables we've described and the number of failed authentication attempts. It has four arguments:

If the maximum number of attempts has been reached, the return value from spc_throttle( ) will be -1. If there is to be no delay, the return value will be 0; otherwise, the return value will be the number of seconds to delay before allowing another authentication attempt.

int spc_throttle(int *attempts, int max_attempts, int allowed_fails, int delay) {
  int exp;
   
  (*attempts)++;
  if (*attempts > max_attempts) return -1;
  if (*attempts <= allowed_fails) return 0;
  for (exp = *attempts - allowed_fails - 1;  exp;  exp--)
    delay *= 2;
  return delay;
}