Hashing and Salting Passwords with Spring Security

Published in Java on 28-Dec-2011

Unfortunately, we quite often hear of websites or businesses, both large and small, getting hacked and having their user databases stolen or otherwise exposed. The results of these kinds of breaches can be catastrophic, particularly if the data that is compromised is of a particularly sensitive nature (credit card numbers, for example) and proper industry-standard precautions haven't been taken.

Most people have dozens of online user accounts – Facebook, your bank, your favorite restaurant review website... the list goes on. Despite experts warning of the dangers, with so many accounts, it is extremely common for users to reuse usernames and passwords on a variety of different sites. This of course means that credentials are easier to remember, but is also means that if any of the sites where login credentials are reused becomes compromised all of your accounts could be in danger.

This is a risk that is manageable using a few common, well known techniques. These techniques can all be implemented in an application manually, but Spring Security includes several components that allow some of these techniques to be applied with very little effort from the developers.

If you are already well versed in the concepts of password hashing and salting, please feel free to jump to the implementation section below. If these concepts are new to you, or you would like a refresher, below is a brief introduction to managing user account passwords.

Background

As application developers, we rely on a huge number of factors for security, many of which are largely out of our control: the operating system, the server software being used, the security framework being used. While we can strive to use secure coding practices, we never know when a fundamental flaw, in the operating system for example, may give a malicious attacker access to our application database – including our user account information.

Fortunately, there are some tried and tested methods that we can implement to minimize the damage that such a breach might cause.

Obviously, if an application stores username and password information in plain text, if the user database is compromised, all of our login credentials are now in the hands of a malicious attacker. It would be trivial for the attacker to look through the list of usernames and passwords, and start entering those credentials into popular websites. It wouldn't take long before he had some success.

Password Hashing

One of the common ways of protecting against this kind of snowballing security risk is to avoid storing passwords in plain text. A process called hashing is commonly used for this purpose. A hash is a one-way function (MD5 and SHA are common examples) that will take a given input (the password) and generate a lengthy string of text. Even if one learns this hashed value, it is almost impossible to programatically deduce the original password. When the application needs to authenticate a user, it asks the user for the password, runs the supplied password through the pre-chosen hashing algorithm, and then compares the resulting hash with the hash value stored in the database. If the values match, the user can be authenticated. So, even if the user database is compromised, all the attacker has is a collection of hash values. Typing those hash values into the password fields of popular websites will do no good – the original password would be required.

This process is not fool-proof however. Many people use simple passwords (“123456”, “password”, “iloveyou” are all very common). When attackers realized this, the began generating something called Rainbow tables. As was mentioned above, given only a hashed value it is almost impossible to calculate what the original password would have been. Instead of attempting to reverse engineer the hash, attackers just started devoting computer processing power to generating lists of all possible hash values for a given set of input characters and a specified algorithm – this is a simplified explanation of a rainbow table. These tables are very large, consuming a great deal of disk space, but make it very easy to take a hash value and figure out what the original password was.

All is not lost, however. The longer the password, and the larger the character set used in the password, the larger a rainbow table must be in order to be able to successfully uncover the original password. With a password of sufficient length, using a large character set, eventually even rainbow tables become infeasible.

So, the solution then is to ensure that all the users of your application use passwords of at least 20 characters in length, containing upper and lower case letters, numbers, symbols, and perhaps a collection of extended ascii characters... Or maybe not.

Adopting password restrictions like that are a sure way to guarantee that your application will have no users. Users are going to want to use passwords that they actually have a chance of remembering and a reasonable likelihood of being able to type in without typos most of the time. This is where the concept of password salting comes in.

Password Salting

A password salt is a collection of characters that the application can easily and repeatedly retrieve. Those characters will be concatenated with the users actual password before the password is fed through the hashing algorithm. This serves two purposes: Firstly, the length of the password is effectively increased by the length of the salt value, dramatically increasing the size of the rainbow table needed to determine the plain-text password from the hash. Additionally, the salt value used can be predefined to contain a wide character set (many different kinds of letters, numbers, symbols, etc), which also substantially increases the size of the necessary rainbow table. When used correctly, this technique all but eliminates the usefulness of rainbow tables for reverse engineering hash values.

It must be noted however that as processing power and the availability of storage space increases, the ability to calculate larger and larger rainbow tables will become easier. So, even salting and hashing isn't fool-proof, but most people agree that it is more than sufficient for the foreseeable future.

Kinds of Salt

There are two primary ways a salt value can be created. Firstly, a system wide value may be chosen. This value could be placed in a configuration file or a database and would then be used to salt all the passwords used in the system.

If an attacker was to learn the salt value, it does not have a huge impact on the security of the system. Knowing the salt value may give an attacker clues about the character set that they must ensure their rainbow table supports, but it does not eliminate the need for a rainbow table nor does it reduce the size of the rainbow table required.

One negative of this approach is that if two different users choose the same password, the resulting password hash for the two accounts will be the same.

This has the potentially vulnerability of an attacker using statistical analysis to determine the plain-text passwords.

For example, if an attacker gained access to an user account database where the passwords were hashed using a value constant across the entire application, and the attacker happened to know that '123456' is the most frequently used password, they could find the most commonly appearing hash value, and given a sufficient sample size, it is likely that value would be the hash that represented '123456'. Of course, this method is not nearly as reliable as having a suitably sized rainbow table, but it does increase the overall vulnerability of the application.

Secondly, an unchanging value, specific to the password's user account can be used as the salt. This could be the username of the account, if the business rules indicated that the username would never change, it could be the surrogate primary key of the record in the database, it could be the account's activation date or any other value that is associated with the user account and known to be immutable. The benefit of this approach is that even if two users on the system choose the same plain-text password, the generated hashes will be different, thereby eliminating the statistical analysis vulnerability discussed above.

It is even possible to combine the two approaches, using a long, system wide value containing a complex character set, appending that to a piece of account specific immutable information and then appending that to the actual password. The best of both worlds can be achieved.

Implementation

We know that we should salt and hash our user account passwords, but how to we achieve this? As with many other tasks, Spring Security has a set of built in components that allow us to implement much of the required functionality in our web application with only a few lines of configuration.

Assuming that we are using a database as our account information store, firstly we need to configure Spring Security to use our database for authentication. After configuring basic form authentication in Spring Security (see the complete application source code below, or the Spring Security documentation if you are unsure of how to accomplish this), adding the following lines to our applicationContext.xml file will allow us to enable basic database authentication:

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/dataSource" resource-ref="true" />
<security:authentication-manager>
    <security:authentication-provider>
        <security:jdbc-user-service data-source-ref="dataSource" />
    </security:authentication-provider>
</security:authentication-manager>

Including this code in your applicationContext.xml file will automatically configure a Spring DaoAuthenticationProvider using a Spring JdbcUserDetailsManager. If you were not to use any hashing or salting, this is actually all that is necessary to allow your application to automatically authenticate against a database (in addition to your controller and JSP page of course). Note that the JdbcUserDetailsManager assumes a fairly naive database schema that could be created using SQL similar to this:

CREATE TABLE USERS (
    username VARCHAR(100) PRIMARY KEY NOT NULL,
    password VARCHAR(100) NOT NULL,
    enabled SMALLINT NOT NULL
);

CREATE TABLE AUTHORITIES (
    username VARCHAR(100) PRIMARY KEY NOT NULL,
    authority VARCHAR(100) NOT NULL,
    CONSTRAINT username_authority_fk FOREIGN KEY (username)
        REFERENCES USERS (username)
);

This schema is likely not suitable for production systems, but Spring allows you to modify the queries that will access and update the user information, thereby allowing you to use a more reasonable schema. Alternatively, you can even replace the JdbcUserDetailsManager entirely with a class of your own creation, allowing you complete flexibility over the implementation.

If you wish to use password hashing and salting however, a little more work is required.

Spring has two interfaces that support various implementations of password hashing and salting:

org.springframework.security.providers.encoding.PasswordEncoder

and

org.springframework.security.authentication.dao.SaltSource

Spring Security comes with several prefabricated implementations of these interfaces. For the purposes of our demonstration, we will be using the ShaPasswordEncoder class in the org.springframework.security.authentication.encoding package and the SystemWideSaltSource from the org.springframework.security.authentication.dao package.

The ShaPasswordEncoder will be used to hash the plain-text passwords using the Secure Hash Algorithm (SHA), and the SystemWideSaltSource will be used to supply a salt value to be used when hashing each password.

First, we will define beans representing these implementations in our applicationContext.xml file:

<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
    <constructor-arg value="256"/>
</bean>

<bean id="saltSource" class="org.springframework.security.authentication.dao.SystemWideSaltSource">
    <property name="systemWideSalt" value="#This,Is9A3Salt*Value;" />
</bean>

When we define the ShaPasswordEncoder above, we specify a constructor argument of 256. This argument is the bit-length of the hash.  The default SHA implementation generates a 160 bit hash and this is the implementation that will be used if a constructor argument is not specified.  There is also a more recent variation on the SHA algorithm that uses 224, 256, 384 or 512 bits.  Generally, greater bit lengths imply a more secure hash, but will take longer to calculate.

The systemWideSalt property of the SystemWideSaltSource allows us to specify the value that will be appended to each password before the passwords are fed through the selected hashing algorithm.  It is a good idea to make this value a fairly lengthy string containing a wide variety of character types. 

Next, instead of allowing Spring Security to automatically configure a DaoAuthenticationProvider and a JdbcUserDetailsManager for us using the <security:authentication-provider> and <security:jdbc-user-service> tags, we will explicitly define them, which allows us to specify configuration values for several of its setter methods:

<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <property name="userDetailsService" ref="userDetailsService" />
    <property name="passwordEncoder" ref="passwordEncoder" />
    <property name="saltSource" ref="saltSource" />
</bean>

<bean id="userDetailsService" class="org.springframework.security.provisioning.JdbcUserDetailsManager">
    <property name="dataSource" ref="dataSource" />
</bean>

As you can see, when we define the DaoAuthenticationProvider we are configuring it to use the password encoder and salt source that we defined above. Now, whenever the authenticate(Authentication auth) method of the DaoAuthenticationProvider is called, it will retrieve the salt value from the SystemWideSaltSource, concatenate it with the password supplied by the user and then pass it through the hashing algorithm indicated by the ShaPasswordEncoder. After comparing this value to the value stored in the database, the user can be authenticated against the system.

As you can see, only a fairly minimal configuration is required to allow you authenticate users against a JDBC database using hashing and password salting. However, this is only one portion of what is necessary to complete the authentication system. Before you can authenticate a user against the application using their salted and hashed password, the user record must exist in the database.

The UserDetailsManager interface, which JdbcUserDetailsManager implements, contains several methods for manipulating user accounts, including creation and deletion. Unfortunately, this implementation, and I believe all the implementations included with Spring Security, have no built in support for salting and hasing passwords. I must admin to being a bit puzzled why it is so remarkably easy to configure Spring Security to authenticate using salted and hashed passwords when similar functionality was not included in the default means by which accounts can be created.

Fortunately, it is not difficult to extend the default behaviour of the JdbcUserDetailsManager to add this functionality.

Firstly, we will create a subclass of JdbcUserDetailsManager, which we will call EnhancedJdbcUserDetailsManager, similar to the following snippet:

public class EnhancedJdbcUserDetailsManager extends JdbcUserDetailsManager {
    private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
    private SaltSource saltSource = null;

    private String encodePassword(
            final String plainTextPassword,
            final UserDetails userDetails) {

        final String salt = saltSource != null
                ? saltSource.getSalt(userDetails).toString()
                : "";
        return this.passwordEncoder.encodePassword(plainTextPassword, salt);
    }
...
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    public void setSaltSource(SaltSource saltSource) {
        this.saltSource = saltSource;
    }
}

Our subclass now contains instance variables to hold a reference to a PasswordEncoder and a SaltSource and setter methods to allow the value of these variables to be set externally. The passwordEncoder instance variable is initially set to a PlaintextPasswordEncoder which is a no-op implmenetation of the PasswordEncoder interface. Additionally, we have added a helper method called encodePassword which will delegate to the PasswordEncoder implementation after having retrieved the appropriate salt value.

Three methods in the UserDetailsManager must be overridden in order to make use of the PasswordEncoder and SaltSource during user management:

createUser and updateUser both take a UserDetails object and use the values in this object (specifically the username, password and isEnabled flag) to generate the SQL to be executed. It is necessary for us to ensure that when the password is retrieved from this object, the salted and hashed value is used rather than the plain-text value. However, we likely don't want to simply set the password value in the UserDetails object to the salted and hashed value as the callers of these methods may not expect the UserDetails object they pass in to be modified. As such, we will create a simple class that wraps the functionality of the UserDetails class, but that will supply the encoded password when asked, rather than the plain-text password - this wrapper object will then be passed to the methods of the JdbcUserDetailsManager super class. This wrapper class will look something like this:

public class UserDetailsEncodedPasswordWrapper implements UserDetails {
    private final UserDetails userDetails;
    private final String encodedPassword;

    public UserDetailsEncodedPasswordWrapper(
                UserDetails userDetails,
                String encodedPassword) {
        this.userDetails = userDetails;
        this.encodedPassword = encodedPassword;
    }

    @Override
    public String getPassword() {
        return this.encodedPassword;
    }

...
/*
Note:  All other methods (removed here for the sake of brevity),
simply delegate to the wrapped UserDetails implementation.
*/
}

Once we have this wrapper class, overriding the relevant methods in our subclass of the JdbcUserDetailsManager is fairly trivial:

private UserDetails getEncodedPasswordUserDetails(final UserDetails user) {
    final String encodedPassword = this.encodePassword(user.getPassword(), user);
    return new UserDetailsEncodedPasswordWrapper(user, encodedPassword);
}

@Override
public void createUser(final UserDetails user) {
    super.createUser(getEncodedPasswordUserDetails(user));
}

@Override
public void updateUser(final UserDetails user) {
    super.updateUser(getEncodedPasswordUserDetails(user));
}

@Override
public void changePassword(String oldPassword, String newPassword)
        throws AuthenticationException {
    final UserDetails user = loadUserByUsername(
            SecurityContextHolder.getContext().getAuthentication().getName());

    super.changePassword(oldPassword, this.encodePassword(newPassword, user));
}

We have added a private method called getEncodedPasswordUserDetails that takes a UserDetails object, calculates the encoded password based on the hashing algorithm and salting process we have defined, and returns a new instance of our UserDetailsEncodedPasswordWrapper that wraps the passed in UserDetails object and will return the encoded password.

For the createUser method and the updateUser method, all we need to do is take the UserDetails object we are passed and call the equivalent method in the super class, passing it the result of the getEncodedPasswordUserDetails call, rather than the original, unwrapped UserDetails object.

The changePassword method is a bit more complicated however as we are not dealing with a UserDetails object supplied by the caller. At first, it may seem that we actually have no need of the UserDetails object, because the method signature simply takes the current password and the desired new password.

The super class implementation (found in JdbcUserDetailsManager) will take the supplied old password and, using the registered AuthenticationProvider, encode the plain-text old password using our hash and salt process, determine the currently logged in user, and ensure that the encoded password matches the stored password. Once this check has completed successfully, the new password specified will be stored. All this happens in the super class implementation, so we don't need to worry ourselves about it too much.

However, what we do need to concern ourselves with is the value of the new password being passed to the super class method. The value passed to us will be the plain-text password. The value stored in the database will be the value passed to the super class method. As such, we must take it upon ourselves to encode the new password correctly before suppling it to the super class changePassword method.

It is important to note that the method signature for the getSalt method of the SaltSource interface requires that a UserDetails object be passed to it. For some implementations of SaltSource this will be irrelevant and null could safely be passed. The implementation we are discussing here, the SystemWideSaltSource, is one of the implemetations that does not require a UserDetails object be passed to it.

Another standard implementation that does however require the UserDetails object is the ReflectionSaltSource, which uses a specified field in the UserDetails object (which should be immutable) as the salt value, eliminating the vulnerability discussed above where two different users that have the same password would have the same password hash.

While, as we have discussed, the implementation we are using does not require the current UserDetails object to be passed to it, it is desirable that we could change the Spring configuration files to use a different implementation of the SaltSource interface without changing the code using those configured classes. As such, we want to ensure that if we were to change the implementation to one which required the UserDetails object the code would not fail. So, we use static methods on the Spring SecurityContextHolder in order to determine the currently authenticated user and retrieve the associated UserDetails object, which then gets passed to our encodePassword private method, and subsequently to the getSalt call.

All that remains is to ensure that we declare our implementation of the EnhancedJdbcUserDetailsManager in our applicationContext.xml file and ensure that our controllers use this UserDetailsManager when adding users, modifying users and changing passwords.

Conclusion

While salting and hashing passwords does not provide perfect mitigation for a breach in security leading to the exposure of usernames and passwords, it does offer considerable protection against the cascading effect this kind of breach can have. The users of your application can at least feel a degree of assurance that all of their user accounts have not been similarly compromised.

With practices like this well known, there is really no excuse for any web site not using these kind of basic protections. While a much better solution would be for users to use different passwords for each of their accounts, at least implementing a salting and hashing system offers users some protection from themselves.

As always, comments, suggestions, criticisms and suggestions are more than welcome. 

Complete Source Code

The source code for a complete, bare-bones sample application is available in zipped format.  It can be built using Maven 3.0 and was tested on Apache Tomcat 6 - although it should deploy successfully on any JEE Compatible container. See the contained readme.txt file for information on usage.

For simplicities sake, the code presented here and in this article uses many defaults that may not be suitable for a production-class application. This includes a very basic database schema for user accounts and other simplifications. Care should be taken when integrating any of these concepts into your own application.

passwordHashSaltSource.zip

References 

Spring 3.0 Security Reference for Hashing and Salting Passwords

FIPS PUB 180-1: Secure Hash Standard

RFC 1321 - MD5 Message Digest Algorithm


About the Author

dan.jpg

Daniel Morton is a Software Developer with Shopify Plus in Waterloo, Ontario and the co-owner of Switch Case Technologies, a software development and consulting company.  Daniel specializes in Enterprise Java Development and has worked and consulted in a variety of fields including WAN Optimization, Healthcare, Telematics, Media Publishing, and the Payment Card Industry.