Hashing and Salting passwords with Spring Security PasswordEncoder

A standard Spring Security configuration uses username / password based authentication. This always presents a tricky problem: how to securely store a user’s password in such a way that it can’t be read by anyone with access to our database. It’s naive to assume that our password database is 100% secure, just ask Adobe, Sony, Ashley Madison, and everyother large organization that has had their database breached. Even if the database isn’t ‘breached’ or ‘leaked’, legitimate database admins or sys admins still have access to user passwords. A database containing user passwords is a liability that we’d rather not have.

The standard solution to this problem is store store a hash of the password rather than the plain text or even encrypted text. I don’t want to focus on why this is good or how it works as many others have done this already. I’ve found no better discussion of this (and password management in general) than Troy Hunt’s post on Everything you ever wanted to know about building a secure password reset feature.

Getting the details right when implementing password storage is critical. Some hash algorithms are vulnerable or just not suited to password hashing. If the salt is too short or predictable, it may be possible to retrieve the password from the hash. Any number of subtle bugs in coding could result in a password database that is vulnerable in one way or another. Fortunately, Spring Security includes password hashing out of the box. What’s more, since version 3.1, Spring Security automatically takes care of salting too.

Spring Security: database backed user authentication

For what it’s worth, I still prefer the old-skool XML namespace configuration over the newfangled Java configuration for Spring Security. I find it to be more readable. The following examples all use the Spring Security XML namespace but would work equally well using Java configuration.

Spring Security offers database backed user authentication allowing a username and password to be verified against a database table:

This will verify a username / password against the
users table of the database referred to via the
dataSource property. The database is set up with the default schema as detailed in the JdbcDaoImpl documentation.

Configuring a Password Encoder

The BCrypt password encoder can be configured simply by having the
authentication-provider refer to it:

XHTML

1

2

3

4

5

<authentication-manager>

<authentication-provider user-service-ref="userDetailsService">

<password-encoder hash="bcrypt"/>

</authentication-provider>

</authentication-manager>

In previous versions of Spring, it was necessary to specify a salt source too. As of version 3.1, all implementations of the new
PasswordEncoder interface take care of salting too.

The above configuration uses the BCrypt password encoder with default settings. If you want to use a non-standard
PasswordEncoder implementation, or if you need to refer to a
PasswordEncoder bean, this is also possible:

User admin

The above configuration of the authentication manager, authentication provider and password encoder deal only with verifying a password on login. We also need some means of creating user accounts with hashed passwords. An obvious way to do this is with a self-service registration page that asks new users to choose a username and password:

The implementation behind this will create a new row in the users table with the given username and password. The
passwordEncoder bean can be reused to create the hash of the password entered by the user. An instance of Spring’s JdbcUserDetailsManager can be used to create the account.
JdbcUserDetailsManager is a subclass of
JdbcDaoImpl (and obviously implements the UserDetailsService interface) so the same bean can be used by the authentication manager to lookup user details on authentication.

XHTML

1

2

3

4

5

6

7

8

9

10

11

12

13

<authentication-manager>

<authentication-provider user-service-ref="userDetailsManager">

<password-encoder ref="passwordEncoder"/>

</authentication-provider>

</authentication-manager>

<!-- UserDetailsManager acts as a UserDetailsService for the authentication provider

and also allows CRUD operations on users and groups. Backed by JDBC - the spanners database. -->

Spring Security also has implementations based on MD4, MD5 and SHA-1 which implement a previous PasswordEncoder interface. This version of the interface is now marked as deprecated as the new one deals better with salting. Confusingly, the implementations are not specifically marked as deprecated. They should however be avoided as they are based on hashing algorithms now known to be insecure. Their only legitimate use is backwards compatibility with legacy applications.

BCrypt is widely accepted as a suitably secure password hashing function. Both OWASP and an excellent explainer on CrackStation recommend BCrypt. PBKDF2 and scrypt are also frequently mentioned as suitable candidates for password encoding but no standard implementation exists for either of these in Spring Security. While it is possible to create a custom implementation of PasswordEncoder using any algorithm, I’d usually recommend sticking to a provided implementation if at all possible.