Most websites are vulnerable to account enumeration, a technique used to discover if a user has an account on a website. The most common features on websites for which there is an account enumeration risk are registration, login, password reset and account recovery.
This is how you can test for this risk at login. Specify the username — which is often the email address — you want to validate and just enter anything in the password field. The login will fail and vulnerable login implementations will disclose whether the particular account exists or not.
This might look benign. Is it such a big deal if someone knows that you have an account on a particular website?
The risks of account enumeration
First of all there’s a privacy risk. Most people are easily identifiable via their username or email address because they use their real name and surname. Certainly when membership of a website is sensitive information you don’t want it to be leaked.
Knowing if a user has an account for a website also poses several security risks such as phishing attacks, extortion, password guessing attacks, and denial-of-service by locking users out of their accounts via password reset.
How to prevent account enumeration
The defense against account enumeration is quite simple in the most cases. The principle is always the same. Whether the user is present in the system or not, always show the same message to the user.
At unsuccessful login, instead of disclosing whether it’s the email address or password that is invalid, show a generic message like for instance Dropbox does.
There’s also a less obvious way in which the presence of a user can be discovered at login, by inspecting the duration of the login requests. It often takes considerably longer when the user exists. But, why’s that?
Websites that properly secure passwords, use slow hashing algorithms to protect against password cracking attacks. These algorithms can consume a few hundreds of milliseconds. When a user exists in the database, the password entered at login will be hashed and checked against the hash stored in the database. When the user doesn’t exist, there’s no need to hash the password provided by the user. This explains the observable difference in timing.
To solve this, websites could either always hash the provided password or add a delay when a user is not present in the database. Be thoughtful though about extending the duration of the login requests. It might become an even bigger attack vector that can be used in Distributed Denial-of-Service (DDoS) attacks. When no proper DDoS protection is in place yet, you might want to address this first.
Also at password reset, Dropbox does a good job by not disclosing the existence of the email address.
However at account registration, Dropbox discloses if a particular email address is already registered.
While many sites already protect against account enumeration at login and password reset, most of them fail to do so at account registration. The fix is simple though. Don’t display whether the email address is already registered or not, but always send an email. Depending on whether the email address is already known in the system or not, the email will respectively explain that the account is already registered or contain a registration link.