User Enumeration Vulnerabilities
Updated: Nov 6, 2021
What do we mean by user enumeration?
User enumeration is a simple class of vulnerability much like any other enumeration of data it means plainly that we are retrieving multiple records, or any other word for data, which in this case includes users. That may be usernames, full names/addresses, or some other information tied to the user, but more or less anything that provides the identity of that user. Most commonly this is usernames, and in almost all cases where we have seen this vulnerability related to user enumeration it involves guessing, or obtaining a list from the target application, of usernames. This enumeration is generally performed via response differences or errors. In example, one of the most well known instances is user enumeration through the forgot password function. In this case we would see an attacker request a list of usernames and based on the response such as "An email has been sent to firstname.lastname@example.org to reset your password" versus "User not found" the attacker can determine which emails are real users to try and login with. This is obviously a low severity finding when the only thing you can obtain is a list of valid usernames, but it enables other attacks such as credential stuffing, or password brute forcing.
Other examples of enumeration
Some other fun user enumeration issues we have seen involved things like REST endpoints meant to show you your own user information (nothing too sensitive) which involve an Insecure Direct Object Reference (IDOR) and look something like this: GET /api/v1/Profile/mccormackcyber Where in this case we would simply iterate through users, numbers, whatever that endpoint takes, this is the IDOR, and we would retrieve info about real users on the system. This is equally true for any other endpoint that accepts a username/user identifier as a parameter. If the API does not simply reject a request for anything besides your own information then you can perform error based enumerations. Another common example, and arguably one that is impossible to remediate without a major hit to the user experience, is simply on a registration form. If I can't register an email to your site its because someone else has it already. Admittedly, remediating that is impractical, but at least remediating it elsewhere like at the forgot password method is still worthwhile. Additionally, other controls such as rate limits could be leveraged to provide a layer of defense here as well. If you do not allow self provisioned user accounts then you have even more reason to remediate all user enumeration abilities.
So how do we fix it?
To remediate this issue there are a few scenarios. In the most common situations such as the forgot password mechanism you simply will return the same message for a true or false check. If my user exists we can say the same thing as if my user does not exist by stating something such as: "If your username was found then an email to reset your password will be sent to the corresponding email address". In the case of error based enumeration on an API the simplest solution is to disallow requests to any users information outside of my own whether live or not. So catch and return the same response, like a 403 forbidden regardless of whether the user exists or not. A deeper solution, and this touches lightly on IDOR as well, is not to allow the user to specify any of these parameters themselves. This can be accomplished by associating the sessionID to the user, an API token to the user, or a JWT containing information you want to identify what records they can obtain (Just remember to sign the JWT with a strong password or key pair). There are probably other ways we can't think of as well, but the idea is to make indirect references to the data you need, or if a direct reference must be used a JWT is your easiest solution as it cannot be easily tampered with by the attacker like a URL or POST parameter.
Are you looking for a security assessment for your network or applications? Send us an email at email@example.com