Preventing username enumeration

Dafydd Stuttard | 22 April 2007 at 11:54 UTC
Authentication

Most people know how to do username enumeration, but not everyone knows how to prevent it. Indeed it is often asserted, incorrectly, that eliminating username enumeration altogether cannot be achieved.

The first step in preventing username enumeration in an application is to identify all of the relevant attack surface. This includes not only the main login but also all of the more peripheral authentication functionality such as account registration, password change and account recovery. It is very common to encounter applications in which username enumeration is not possible in the main login function, but can be trivially performed elsewhere.

The second step is to ensure, in every piece of relevant functionality, that the application does not provide a means for an attacker to confirm the validity or otherwise of an arbitrarily chosen username. This is not just a matter of fixing obvious failure messages such as "username incorrect" vs. "password incorrect", but also of checking every aspect of the application's behaviour. For example, if the same literal on-screen failure message is generated by different code paths, then subtle differences may arise within the HTML source. Alternatively, the application may manifest timing differences when processing valid and invalid usernames, because different database queries and computational operations are performed when a valid username is supplied.

Of the various points of attack surface, account registration functionality can seem to be the most difficult area in which to eliminate username enumeration, If an existing username is chosen, surely the application must reject the registration attempt in some manner, enabling an attacker to infer which usernames have been registered? Using CAPTCHA controls and other hurdles may slow down the process, but they do not prevent it.

In fact, there are two ways in which an account registration function can be implemented which avoid introducing enumeration vulnerabilities: