8.8 Throttling Failed Authentication Attempts

8.8.1 Problem

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

8.8.2 Solution

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.

8.8.3 Discussion

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:

Maximum number of attempts

If this limit is reached, the authentication should be considered a complete failure, resulting in a disconnection of the network connection or shutting down of the program that requires authentication. A reasonable limit on the maximum number of allowed authentication attempts is three, or perhaps five at most.

Maximum number of failed attempts allowed before enabling throttling

In general, it is reasonable to allow one or two failed attempts before instituting delays, depending on the maximum number of allowed authentication failures.

Number of seconds to delay between successive authentication attempts

For each successive failure, the delay increases exponentially. For example, if the base number of seconds to delay is set to two, the first delay will be two seconds, the second delay will be four seconds, the third delay will be eight seconds, and so on. A reasonable starting delay is generally one or two seconds, but depending on the settings you choose for the first two variables, you may want to increase the starting delay. In particular, if you allow a large number of attempts, it is probably a good idea to increase the delay.

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.

Some of these techniques can increase the risk of denial-of-service attacks.

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:


Pointer to an integer used to count the number of failed attempts. Initially, the value of the integer to which it points should be zero, and each call to spc_throttle( ) will increment it by one.


Maximum number of attempts to allow. When this number of attempts has been made, the return from spc_throttle( ) will be -1 to indicate a complete failure to authenticate.


Number of attempts allowed before enabling throttling.


Base delay in seconds.

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;
  if (*attempts > max_attempts) return -1;
  if (*attempts <= allowed_fails) return 0;
  for (exp = *attempts - allowed_fails - 1;  exp;  exp--)
    delay *= 2;
  return delay;