User enumeration refers to the ability to guess existing usernames in a web application database. This can happen, for example, when using "sign-in/sign-on/forgot password" functionalities of a website.
When an user tries to "sign-in" to a website with an incorrect username/login, the web application should not disclose that the username doesn't exist with a message similar to "this username is incorrect", instead a generic message should be used like "bad credentials", this way it's not possible to guess whether the username or password was incorrect during the authentication.
If a user-management feature discloses information about the existence of a username, attackers can use brute force attacks to retrieve a large amount of valid usernames that will impact the privacy of corresponding users and facilitate other attacks (phishing, password guessing etc ...).
There is a risk if you answered yes to any of those questions.
When a user performs a request involving a username, it should not be possible to spot differences between a valid and incorrect username:
In a Spring-security web application the username leaks when:
public String authenticate(String username, String password) { // .... MyUserDetailsService s1 = new MyUserDetailsService(); MyUserPrincipal u1 = s1.loadUserByUsername(username); if(u1 == null) { throw new BadCredentialsException(username+" doesn't exist in our database"); // Sensitive } // .... }
public String authenticate(String username, String password) { // .... if(user == null) { throw new UsernameNotFoundException("user not found"); // Sensitive } // .... }
DaoAuthenticationProvider daoauth = new DaoAuthenticationProvider(); daoauth.setUserDetailsService(new MyUserDetailsService()); daoauth.setPasswordEncoder(new BCryptPasswordEncoder()); daoauth.setHideUserNotFoundExceptions(false); // Sensitive builder.authenticationProvider(daoauth);
In a Spring-security web application:
public String authenticate(String username, String password) throws AuthenticationException { Details user = null; try { user = loadUserByUsername(username); } catch (UsernameNotFoundException | DataAccessException e) { // Hide this exception reason to not disclose that the username doesn't exist } if (user == null || !user.isPasswordCorrect(password)) { // User should not be able to guess if the bad credentials message is related to the username or the password throw new BadCredentialsException("Bad credentials"); } }
DaoAuthenticationProvider daoauth = new DaoAuthenticationProvider(); daoauth.setUserDetailsService(new MyUserDetailsService()); daoauth.setPasswordEncoder(new BCryptPasswordEncoder()); daoauth.setHideUserNotFoundExceptions(true); // Compliant builder.authenticationProvider(daoauth);