8.8.1 ProblemYou want to prevent an attacker from making too many attempts at guessing a password through normal interactive means. 8.8.2 SolutionIt'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 DiscussionThrottling 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; } |