Spring Security: Configuring Secure Passwords

Exclusive offer: get 50% off this eBook here
Spring Security 3

Spring Security 3 — Save 50%

Secure your web applications against malicious intruders with this easy to follow practical guide

£18.99    £9.50
by Peter Mularien | May 2010 | Java Open Source Web Development

This article by Peter Mularien is an excerpt from the book Spring Security 3.

In this article, we will:

  • Examine different methods of configuring password encoding
  • Understand the password salting technique of providing additional security to stored passwords

(For more resources on Spring, see here.)

In any secured system, password security is a critical aspect of trust and authoritativeness of an authenticated principal. Designers of a fully secured system must ensure that passwords are stored in a way in which malicious users would have an impractically difficult time compromising them.

The following general rules should be applied to passwords stored in a database:

  • Passwords must not be stored in cleartext (plain text)
  • Passwords supplied by the user must be compared to recorded passwords in the database
  • A user's password should not be supplied to the user upon demand (even if the user forgets it)

For the purposes of most applications, the best fit for these requirements involves one-way encoding or encryption of passwords as well as some type of randomization of the encrypted passwords. One-way encoding provides the security and uniqueness properties that are important to properly authenticate users with the added bonus that once encrypted, the password cannot be decrypted.

In most secure application designs, it is neither required nor desirable to ever retrieve the user's actual password upon request, as providing the user's password to them without proper additional credentials could present a major security risk. Most applications instead provide the user the ability to reset their password, either by presenting additional credentials (such as their social security number, date of birth, tax ID, or other personal information), or through an email-based system.

Storing other types of sensitive information Many of the guidelines listed that apply to passwords apply equally to other types of sensitive information, including social security numbers and credit card information (although, depending on the application, some of these may require the ability to decrypt). It's quite common for databases storing this type of information to represent it in multiple ways, for example, a customer's full 16-digit credit card number would be stored in a highly encrypted form, but the last four digits might be stored in cleartext (for reference, think of any internet commerce site that displays XXXX XXXX XXXX 1234 to help you identify your stored credit cards).

You may already be thinking ahead and wondering, given our (admittedly unrealistic) approach of using SQL to populate our HSQL database with users, how do we encode the passwords? HSQL, or most other databases for that matter, don't offer encryption methods as built-in database functions.

Typically, the bootstrap process (populating a system with initial users and data) is handled through some combination of SQL loads and Java code. Depending on the complexity of your application, this process can get very complicated.

For the JBCP Pets application, we'll retain the embedded-database declaration and the corresponding SQL, and then add a small bit of Java to fire after the initial load to encrypt all the passwords in the database. For password encryption to work properly, two actors must use password encryption in synchronization ensuring that the passwords are treated and validated consistently.

Spring Security: Configuring Secure Passwords

Password encryption in Spring Security is encapsulated and defined by implementations of the o.s.s.authentication.encoding.PasswordEncoder interface. Simple configuration of a password encoder is possible through the <password-encoder> declaration within the <authentication-provider> element as follows:

<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="jdbcUserService">
<password-encoder hash="sha"/>
</authentication-provider>
</authentication-manager>

You'll be happy to learn that Spring Security ships with a number of implementations of PasswordEncoder, which are applicable for different needs and security requirements. The implementation used can be specified using the hash attribute of the <password-encoder> declaration.

The following table provides a list of the out of the box implementation classes and their benefits. Note that all implementations reside in the o.s.s.authentication. encoding package.

Implementation class

Description

hash value

PlaintextPasswordEncoder

Encodes the password

as plaintext. Default

DaoAuthenticationProvider

password encoder.

plaintext

Md4PasswordEncoder

PasswordEncoder utilizing the

MD4 hash algorithm. MD4 is not

a secure algorithm-use of this

encoder is not recommended.

md4

Md5PasswordEncoder

PasswordEncoder utilizing the

MD5 one-way encoding algorithm.

md5

ShaPasswordEncoder

PasswordEncoder utilizing the SHA

one-way encoding algorithm. This

encoder can support confi gurable

levels of encoding strength.

Sha

 

sha-256

LdapShaPasswordEncoder

Implementation of LDAP SHA

and LDAP SSHA algorithms

used in integration with LDAP

authentication stores.

{sha}

 

{ssha}

As with many other areas of Spring Security, it's also possible to reference a bean definition implementing PasswordEncoder to provide more precise configuration and allow the PasswordEncoder to be wired into other beans through dependency injection. For JBCP Pets, we'll need to use this bean reference method in order to encode the bootstrapped user data.

Let's walk through the process of configuring basic password encoding for the JBCP Pets application.

Configuring password encoding

Configuring basic password encoding involves two pieces—encrypting the passwords we load into the database after the SQL script executes, and ensuring that the DaoAuthenticationProvider is configured to work with a PasswordEncoder.

Configuring the PasswordEncoder

First, we'll declare an instance of a PasswordEncoder as a normal Spring bean:

<bean class="org.springframework.security.authentication.
encoding.ShaPasswordEncoder" id="passwordEncoder"/>

You'll note that we're using the SHA-1 PasswordEncoder implementation. This is an efficient one-way encryption algorithm, commonly used for password storage.

Configuring the AuthenticationProvider

We'll need to configure the DaoAuthenticationProvider to have a reference to the PasswordEncoder, so that it can encode and compare the presented password during user login. Simply add a <password-encoder> declaration and refer to the bean ID we defined in the previous step:

<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="jdbcUserService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>

Try to start the application at this point, and then try to log in. You'll notice that what were previously valid login credentials are now being rejected. This is because the passwords stored in the database (loaded with the bootstrap test-users-groupsdata. sql script) are not stored in an encrypted form that matches the password encoder. We'll need to post-process the bootstrap data with some simple Java code.

Writing the database bootstrap password encoder

The approach we'll take for encoding the passwords loaded via SQL is to have a Spring bean that executes an init method after the embedded-database bean is instantiated. The code for this bean, com.packtpub.springsecurity.security. DatabasePasswordSecurerBean, is fairly simple.

public class DatabasePasswordSecurerBean extends JdbcDaoSupport {
@Autowired
private PasswordEncoder passwordEncoder;

public void secureDatabase() {
getJdbcTemplate().query("select username, password from users",
new RowCallbackHandler(){
@Override
public void processRow(ResultSet rs) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
String encodedPassword =
passwordEncoder.encodePassword(password, null);
getJdbcTemplate().update("update users set password = ?
where username = ?", encodedPassword,username);
logger.debug("Updating password for username:
"+username+" to: "+encodedPassword);
}
});
}
}

The code uses the Spring JdbcTemplate functionality to loop through all the users in the database and encode the password using the injected PasswordEncoder reference. Each password is updated individually.

Spring Security 3 Secure your web applications against malicious intruders with this easy to follow practical guide
Published: May 2010
eBook Price: £18.99
Book Price: £30.99
See more
Select your format and quantity:

(For more resources on Spring, see here.)

Configuring the bootstrap password encoder

We need to configure the Spring bean declaration such that the bean is initialized upon start of the web application and after the <embedded-database> bean. Spring bean dependency tracking ensures that the DatabasePasswordSecurerBean executes at the proper time:

<bean class="com.packtpub.springsecurity.security.
DatabasePasswordSecurerBean"
init-method="secureDatabase" depends-on="dataSource">
<property name="dataSource" ref="dataSource"/>
</bean>

If you start the JBCP Pets application at this point, you'll see that the passwords in the database are encoded, and login now functions properly.

Would you like some salt with that password?

If the security auditor were to examine the encoded passwords in the database, he'd find something that would still make him concerned about the website's security. Let's examine what the stored username and password values are for our admin and guest users:

Username

Plaintext password

Encrypted password

admin

admin

7b2e9f54cdff413fcde01f330af6896c3cd7e6cd

guest

guest

2ac15cab107096305d0274cd4eb86c74bb35a4b4

This looks very secure—the encrypted passwords obviously bear no resemblance to the original passwords. What could the auditor be concerned about? What if we add a new user who happens to have the same password as our admin user?

Username

Plaintext Password

Encrypted Password

fakeadmin

admin

7b2e9f54cdff413fcde01f330af6896c3cd7e6cd

Now, note that the encrypted password of the fakeadmin user is exactly the same as the real admin user! Thus a hacker who had somehow gained the ability to read the encrypted passwords in the database could compare their known password's encrypted representation with the unknown one for the admin account, and see they are the same! If the hacker had access to an automated tool to perform this analysis, they could likely compromise the administrator's account within a matter of hours.

Having personally worked with a database where passwords were encrypted in exactly this way, my engineering team and I decided to run a little experiment and see what the SHA-1 encrypted value of the plaintext password password was. We then took the encrypted form of the word password and ran a database query to see how many users in the database had this highly insecure password. To our surprise and dismay, we found many, including a VP of the organization. Each user got a nice follow-up email reminder about the benefits of choosing a hard to guess password, and development quickly got to work on a more secure password encryption mechanism!

Some hacking techniques take advantage of the fact that hash algorithms are deterministic—the same input always leads to the same output, and as such, if an attacker tries enough inputs, they may happen to match an unknown output to the result of a known input.

One common, and effective, method of adding another layer of security to encrypted passwords is to incorporate a salt. A salt is a second plaintext component which is concatenated with the plaintext password prior to encryption in order to ensure that two factors must be used to generate (and thus compare) encrypted password values. Properly selected salts can guarantee that no two passwords will ever have the same encrypted value, thus preventing the scenario that concerned our auditor, and avoiding many common types of brute force password cracking techniques.

Best practice salts generally fall into one of two categories:

  • They are algorithmically generated from some piece of data associated with the user—for example, the timestamp that the user was created
  • They are randomly generated, and stored in some form (plaintext or two-way encrypted) along with the user's password record

For example, the following diagram illustrates the simple case where the salt is the same as the user's login name:

Spring Security: Configuring Secure Passwords

Remember that because the salt is added to the plaintext password, the salt can't be one-way encrypted—the application needs to be able to look up or derive the appropriate salt value for a given user's record in order to authenticate the user!

Spring Security provides us with an interface, o.s.s.authentication.dao. SaltSource, which defines a method to return a salt value from the UserDetails object, along with two out of the box implementations:

  • SystemWideSaltSource defines a single, static salt used for every password. This is not significantly more secure than an unsalted password.
  • ReflectionSaltSource uses a bean property of the UserDetails object to get the salt value for that user's password.

Since salt values should be derivable from, or stored with each user record, ReflectionSaltSource is the out of the box implementation that most implementers typically use.

Configuring a salted password

As with configuring basic password encryption in the previous exercise, adding elements to support a salted password requires changes in both the bootstrap code and the DaoAuthenticationProvider We can examine how the workflow of salted passwords changes bootstrap and authentication by revising the following diagram:

Spring Security: Configuring Secure Passwords

Let's add a level of password security by configuring the ReflectionSaltSource to salt our passwords!

Declaring the SaltSource Spring bean

In dogstore-base.xml, add a bean declaration for the SaltSource implementation we're using:

<bean class="org.springframework.security.authentication.
dao.ReflectionSaltSource" id="saltSource">
<property name="userPropertyToUse" value="username"/>
</bean>

We're configuring the salt source to use the username property, but this is a short-term implementation that we'll correct in a later exercise. Can you think why this might not be a good salt value?

Wiring the PasswordEncoder to the SaltSource

We'll need to hook up the SaltSource to the PasswordEncoder, so that the credentials the user presents upon login can be appropriately salted, prior to comparison with stored values. This is done by adding a new declaration in dogstore-security.xml:

<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="jdbcUserService">
<password-encoder ref="passwordEncoder">
<salt-source ref="saltSource"/>
</password-encoder>
</authentication-provider>
</authentication-manager>

You'll note that if you start up the application at this point, you won't be able to log in. Just as in the previous exercise, the bootstrap database password encoder bean needs to be modified to include the SaltSource.

Augmenting DatabasePasswordSecurerBean

We'll add a bean reference to the DatabasePasswordSecurerBean, as well as a reference to the UserDetailsService so that we can get the appropriate password salt for the user:

public class DatabasePasswordSecurerBean extends JdbcDaoSupport {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private SaltSource saltSource;
@Autowired
private UserDetailsService userDetailsService;

public void secureDatabase() {
getJdbcTemplate().query("select username, password from users",
new RowCallbackHandler(){
@Override
public void processRow(ResultSet rs) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
UserDetails user =
userDetailsService.loadUserByUsername(username);
String encodedPassword =
passwordEncoder.encodePassword(password,
saltSource.getSalt(user));
getJdbcTemplate().update("update users set password = ?
where username = ?",
encodedPassword,
username);
logger.debug("Updating password for username:
"+username+" to: "+encodedPassword);
}
});
}
}

Recall that the SaltSource relies on a UserDetails object to generate the salt value. At this point, as we don't have the database row mapped to a UserDetails object, we'll have to make a request to the UserDetailsService (our CustomJdbcDaoImpl) to look up the UserDetails based on the username from the SQL query response.

At this point, we should be able to start the application and properly log into the system. If you try adding a new user with the same password (for example, admin) to the bootstrap SQL script, you'll note that the password generated for the user is different, because we're salting the passwords with the username. This makes the passwords much more secure in the unlikely event that a malicious user is able to read the passwords from the database. However, you may have some ideas as to why using the username isn't the most secure possible salt—we'll explore this in a later exercise.

Spring Security 3 Secure your web applications against malicious intruders with this easy to follow practical guide
Published: May 2010
eBook Price: £18.99
Book Price: £30.99
See more
Select your format and quantity:

(For more resources on Spring, see here.)

Enhancing the change password functionality

One important change that we'll need to make is to update the changePassword functionality to refer to the password encoder implementation as well. This is as simple as adding appropriate bean references to the CustomJdbcDaoImpl class, and minor code changes in the changePassword method:

public class CustomJdbcDaoImpl extends JdbcDaoImpl {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private SaltSource saltSource;

public void changePassword(String username, String password) {
UserDetails user = loadUserByUsername(username);
String encodedPassword = passwordEncoder.encodePassword
(password, saltSource.getSalt(user));
getJdbcTemplate().update(
"UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?",
encodedPassword, username);
}

The use of the PasswordEncoder and SaltSource here will ensure that the user's password is properly salted when changed. Curiously, use of a PasswordEncoder and SaltSource is not supported by the JdbcUserDetailsManager, so if you are using JdbcUserDetailsManager as a baseline for customization, you will need to override quite a bit of code.

Configuring a custom salt source

As mentioned when we first configured password salting, username is a feasible, but not extremely desirable, choice for a password salt. The reason for this is that username is a salt that is under direct control of the user. If users are provided with the ability to change their username, it would be possible for malicious users to continuously change their user names—thus re-salting their passwords—and possibly determine how to construct a falsely encrypted password.

More secure still would be to have a property of the UserDetails which is chosen by the system, and never visible to, or modifiable by the user. We'll add a property to the UserDetails object that is populated at random when a user is created. This property will become the user's salt.

Extending the database schema

We'll need to ensure that the salt is stored in the database along with the user record, so we'll add a column to the default Spring Security database schema, defined in security-schema.sql:

create table users(
username varchar_ignorecase(50) not null primary key,
password varchar_ignorecase(50) not null,
enabled boolean not null,
salt varchar_ignorecase(25) not null
);

Next, add the bootstrap salt values to the test-users-groups-data.sql script:

insert into users(username, password, enabled, salt) values ('admin','
admin',true,CAST(RAND()*1000000000 AS varchar));
insert into users(username, password, enabled, salt) values ('guest','
guest',true,CAST(RAND()*1000000000 AS varchar));

Remember, we're replacing the insert statements that are already there with these new ones. Note that we've chosen salt values based on random number generation—any pseudo-random salt selection of your choice can be just as effective.

Tweaking configuration of the CustomJdbcDaoImpl UserDetails service

We'll add a configuration change to the query used to retrieve users from the database in order to pick up the additional 'salt' column. We'll modify the CustomJdbcDaoImpl bean definition in dogstore-security.xml:

<beans:bean id="jdbcUserService"
class="com.packtpub.springsecurity.security.CustomJdbcDaoImpl">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="enableGroups" value="true"/>
<beans:property name="enableAuthorities" value="false"/>
<beans:property name="usersByUsernameQuery">
<beans:value>select username,password,enabled,
salt from users where username = ?
</beans:value>
</beans:property>
</beans:bean>

Overriding the baseline UserDetails implementation

We'll need a UserDetails implementation that tracks the salt value stored with the user record in the database. Simply overriding the Spring standard User class is sufficient for our purposes. Remember to add a getter and setter for the salt, so that the ReflectionSaltSource password salter can find the right property.

package com.packtpub.springsecurity.security;
// imports
public class SaltedUser extends User {
private String salt;
public SaltedUser(String username, String password,
boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, List<GrantedAuthority>
authorities, String salt) {
super(username, password, enabled,
accountNonExpired, credentialsNonExpired,
accountNonLocked, authorities);
this.salt = salt;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
}

Even though we are extending the UserDetails to capture a salt field, the process would be the same if we wanted to store additional information about the user from a backing store. Extension of the UserDetails object is commonly done in conjunction with the implementation of a custom AuthenticationProvider.

Extending the functionality of CustomJdbcDaoImpl

We need to override the methods of JdbcDaoImpl, responsible for instantiating the UserDetails implementation that sets the default values for User. This occurs while loading the User from the database, and then copying the User into the instance that actually gets returned from the UserDetailsService:

public class CustomJdbcDaoImpl extends JdbcDaoImpl {
public void changePassword(String username, String password) {
getJdbcTemplate().update(
"UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?"
password, username);
}
@Override
protected UserDetails createUserDetails(String username,
UserDetails userFromUserQuery,
List<GrantedAuthority> combinedAuthorities) {
String returnUsername = userFromUserQuery.getUsername();
if (!isUsernameBasedPrimaryKey()) {
returnUsername = username;
}
return new SaltedUser(returnUsername,
userFromUserQuery.getPassword(),userFromUserQuery.isEnabled(),
true, true, true, combinedAuthorities,
((SaltedUser) userFromUserQuery).getSalt());
}
@Override
protected List<UserDetails> loadUsersByUsername(String username) {
return getJdbcTemplate().
query(getUsersByUsernameQuery(),
new String[] {username},
new RowMapper<UserDetails>() {
public UserDetails mapRow(ResultSet rs, int rowNum)
throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
String salt = rs.getString(4);
return new SaltedUser(username, password,
enabled, true, true, true,
AuthorityUtils.NO_AUTHORITIES, salt);
}
});
}
}

The methods createUserDetails and loadUsersByUsername are adapted from the superclass methods—the changes from the superclass methods are highlighted in the code listing. With these changes, you should be able to restart the application and have extra secure, randomly salted passwords. You may wish to add logging, and experiment, to see how the encrypted values change on every run of the application, as the bootstrap users are loaded.

Keep in mind that although this example illustrated the addition of a simple field to the UserDetails implementation, this approach can be used as a baseline to a highly customized UserDetails object which fits the business needs of your application. For the purposes of JBCP Pets, the auditors are now sufficiently happy with the security of passwords in the database—a job well done!

Summary

This article covered the important security concepts around safe password storage.


Further resources on this subject:


About the Author :


Peter Mularien

Peter Mularien is an experienced software architect and engineer, and the author of the book Spring Security 3, Packt Publishing. Peter currently works for a large financial services company and has over 12 years consulting and product experience in Java, Spring, Oracle, and many other enterprise technologies. He is also the reviewer of this book.

Books From Packt


Groovy for Domain-Specific Languages
Groovy for Domain-Specific Languages

GlassFish Security
GlassFish Security

iReport 3.7
iReport 3.7

Pentaho 3.2 Data Integration: Beginner's Guide
Pentaho 3.2 Data Integration: Beginner's Guide

Django 1.2 E-commerce
Django 1.2 E-commerce

WordPress and Flash 10x Cookbook
WordPress and Flash 10x Cookbook

jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

Drupal 7 First look
Drupal 7 First look

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software