del.icio.us Digg DZone Reddit StumbleUpon
Hashing and Salting Passwords with Spring Security 2 - Willie Wheeler
« Previous | 1 | 2 | 3 | 4 | 5 | 6 | Next »

Add a little salt to that hash

kevindooley
Photo credit: kevindooley

Ideally we'd like to thwart even the semi-determined attacker. To improve our scheme, we now introduce the idea of salt.

The strategy behind salt is to make it much more painful for the attacker to recover hashed passwords. Instead of allowing ourselves to be attacked by a single well-known dictionary, we are going to force the attacker to create a new and unique dictionary for every single password he wants to try to recover. Can he still do it? Sure. But it's just a lot more work now. We've effectively eliminated merely semi-determined attackers from the pool of attackers. That's nothing to scoff at since their numbers are large.

Here's how we do it. Instead of hashing passwords, we concatenate a string—called a salt—to the plaintext password, and then hash the concatenated string. This effectively breaks the standard dictionary attack, because now all of the hashes in your password store are "new."

What happens, though, if we use a single, common salt across all users? While this is better than using no salt at all, it's still not hard to overcome if the attacker knows the salt. The attacker simply has to create a single new dictionary, this time concatenating the salt to each individual dictionary word before hashing. Then it's the same as before.

We want to make things harder for him. Instead of using a common salt across all users, we want the salt to be different for each user. That way, the attacker has to create a new dictionary for every single user he wants to attack. Again, he can do it, but it's much more time-consuming.

One good way to create a salt is to use some property of the user. It is better to choose something that won't change, such as a numeric primary key, than it is to choose something that might change, such as an e-mail address. If you use (say) e-mail addresses for salt, and a user changes his e-mail address, he won't be able to log in anymore because the authentication system won't be able to create the correct hash.

Usernames are a reasonable choice as they don't usually change, but a numeric primary key is even better, given the specific scheme Spring Security uses to concatenate the password with the salt. Spring Security uses braces to delimit the salt, and hence disallows braces inside the salt itself. For example, if my password/salt is college/willie, then Spring Security will hash the string college{willie}. You may well want to allow braces in the username (it's common for gamers to include such characters in their usernames). You can avoid the whole issue—including the added complexity of disallowing braces in usernames—by using the user's numeric primary key, if the user schema supports that.

So let's do just that.

Update applicationContext-security.xml to handle salt

All we need to do to applicationContext-security.xml is add a SaltSource bean and inject it into the DaoAuthenticationProvider. We do this in listing 3 below.

Listing 3. Adding a salt source to your configuration
<beans:bean id="passwordEncoder"
    class="org.springframework.security.providers.encoding.ShaPasswordEncoder" />
<beans:bean id="saltSource"
    class="org.springframework.security.providers.dao.salt.ReflectionSaltSource"
    p:userPropertyToUse="id" />
<beans:bean
    class="org.springframework.security.providers.dao.DaoAuthenticationProvider"
    p:userDetailsService-ref="userDetailsService"
    p:passwordEncoder-ref="passwordEncoder"
    p:saltSource-ref="saltSource">
    <custom-authentication-provider />
</beans:bean>

We mentioned above that it's possible to use a global salt, but that it's not as good as using a salt that varies from user to user. (For a more detailed explanation, please see my article Storing Passwords Security.) ReflectionSaltSource allows us to use a property of our user (specifically, a property of a UserDetails instance; we'll see that shortly) to provide a salt. As with the PasswordEncoder, we've defined the SaltSource explicitly as a bean so we can inject it into AccountServiceImpl.

Update AccountServiceImpl to salt the password

The first step is to add a setter for a SaltSource instance to AccountServiceImpl, and wire it up in your application context file.

Next, we'll once again update registerAccount() in listing 4.

Listing 4. Update your registration method to handle salt
public void registerAccount(Account account) {
	accountDao.save(account);
	UserDetailsAdapter userDetails = new UserDetailsAdapter(account); // 1
	String password = userDetails.getPassword();
	Object salt = saltSource.getSalt(userDetails); // 2
	account.setPassword(passwordEncoder.encodePassword(password, salt)); // 3
	accountDao.save(account);
}

As before, we're saving the account with a plaintext password first. I promised earlier to explain why I'm doing that, so here's the explanation. In many cases (such as when using Hibernate), entities aren't assigned IDs until after they're persisted. Since we're basing our salt on the ID, we need to save the account before generating the salt and hash.

Next we wrap the account with a class we wrote to adapt our Account class to the UserDetails interface; namely, UserDetailsAdapter 1 (we'll see it momentarily).

We're using the SaltSource to get the salt from our UserDetailsAdapter 2. As we saw in the configuration, this salt source uses reflection to grab the account ID and present it to the PasswordEncoder as salt 3.

Listing 5 shows our UserDetailsAdapter class, which again is just an example of a UserDetails implementation. I'm extending the org.springframework.security.userdetails.User class for convenience, but note that that's a UserDetails implementation.

Listing 5. A sample UserDetails implementation
package examples;

import java.util.Set;

import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.User;

public class UserDetailsAdapter extends User { // 1
	private final Long id;
	
	public UserDetailsAdapter(Account acct) {
		super(acct.getUsername(), acct.getPassword(), acct.isEnabled(),
				true, true, true, toAuthorities(acct.getAuthorityNames()));
		this.id = acct.getId();
	}
	
	private static GrantedAuthority[] toAuthorities(Set<String> authNames) {
		GrantedAuthority[] auths = new GrantedAuthority[authNames.size()];
		int i = 0;
		for (String authName : authNames) {
			auths[i++] = new GrantedAuthorityImpl(authName);
		}
		return auths;
	}
	
	public Long getId() {
		return id;
	}
}

Again, we're just extending User for convenience 1; the important thing is that our UserDetailsAdapter implements UserDetails, which allows DaoAuthenticationProvider to use it to perform authentication.

There you have it—salted and hashed passwords. This won't stop the most determined attackers from unmasking your passwords, but it will stop most others.

Social bookmarks: del.icio.us Digg DZone Reddit StumbleUpon
« Previous | 1 | 2 | 3 | 4 | 5 | 6 | Next »

Comments (14)

Very nice article Willie... thanks
By Hema on Oct 12, 2008 at 8:44 PM PDT
Good work Dudes
By Mustafa Sait Özen on Oct 12, 2008 at 11:57 PM PDT

Nice article. Fills in a few gaps in the Spring Security documentation!

By Ross Duncan on Feb 25, 2009 at 9:35 AM PST

Hello Willie,

Do I need a custom UserDetailsServiceImpl for this?

Because I tried to do this with JdbcDaoImpl, like this:

<-- 2 -- >

class="org.springframework.security.userdetails.jdbc.JdbcDaoImpl"

p:userDao="accountDao" />

but I received a NotWritablePropertyException:

SEVERE: Servlet /FlexServer threw load() exception org.springframework.beans.NotWritablePropertyException: Invalid property 'userDao' of bean class [org.springframework.security.userdetails.jdbc.JdbcDaoImpl]: Bean property 'userDao' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter? at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:787) at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:643)

Thanks in advance, and for this very interesting article (as usual),

Greets, Jochen

By Jochen Szostek on Jun 13, 2009 at 2:00 PM PDT

Correct me if i am wrong but the line number 5 in listing 4:

Object salt = saltSource.getSalt(userDetails); 

is bound to return in the variable salt the Long representing the id of the object account. So why not use the id directly. That way we would simplify the code to something like this:

public void registerAccount(Account account) {  
accountDao.save(account);  
account.setPassword(passwordEncoder.encodePassword(password,  account.getId())); 
accountDao.save(account);  
} 

Am I oversimplifying. Please correct me if I am wrong since I will be using this stuff in a project. Thanks for the nice article.

Stole

By stole on Aug 20, 2009 at 1:52 PM PDT

I was a little hasty while submitting the post previously. The code should have read:

public void registerAccount(Account account) {  
 accountDao.save(account);  
 account.setPassword(
    passwordEncoder.encodePassword(account.getPassword(), account.getId()));
 accountDao.save(account);
} 

Stole

By stole on Aug 20, 2009 at 2:27 PM PDT

Ah. Sometimes one has to say a lot more in order not to repeat oneself.

By stole on Aug 20, 2009 at 10:19 PM PDT

The answer as to why you shouldn't change the code is simple. It may seam as a simplification to you, but in fact doing what you're proposing will make it harder to change the salt afterwards.

In case you want to switch from the id to something else as the salt you could simply change it in your security config.

p:userPropertyToUse="id" /> 
By muskatus on Sep 15, 2009 at 9:25 AM PDT

The main reason I would offer is this. There are two cases where you access the password: during account creation, and during authentication. A DaoAuthenticationProvider handles the authentication case and to use that, you need to inject it with a salt source. By using that same salt source during registration, you don't have to worry about manually syncing the two cases in the event that you decide to use something other than the ID: you would just change the XML configuration of the salt source itself.

Know that response is pretty late but hopefully it helps anyway.

By Willie Wheeler on Sep 16, 2009 at 12:40 AM PDT

...another way to say the same thing is that this is basically a DRY move.

By Willie Wheeler on Sep 16, 2009 at 12:45 AM PDT

I initially found your article because I couldn't find any documentation in Spring on how they mix the salt with the password. Thanks for letting me know about the braces e.g. password {salt}. By the way, how did you find that out? I'm frustrated that I couldn't find that from my reading of the documentation.

Decided to read your article and it cleared up a lot of confusion I had about the configuration - especially surrounding the authentication provider. I was declaring an authentication manager bean and the necessary list of providers. Nice to know I didn't need to do that but simply had to use the security:custom-authentication-provider tag!

Great article - thank you.

PUK

By PUK on Oct 27, 2009 at 8:02 AM PDT

I've got a question about configuration. I've got two configuration files: security in one xml config (referenced from web.xml), and another xml config for the main dispatcher servlet (dispatcher-servlet.xml).

I already have a userDAO which is configured in the dispatcher-servlet.xml. This needs to be dependency injected into the UserDetailsService so I've repeated the userDAO bean in the security xml config too. This repitition is bad.

Additionally, I want to use the password encoder and salt source within a controller bean. Therefore I need to DI the password encoder and salt source beans into the controller bean. They're defined in different xml files.

How does someone get around this problem?

Thanks,

PUK

By PUK on Oct 27, 2009 at 8:20 AM PDT

@PUK: Glad to know the article helped. Yeah, on the namespace config, that's a pretty nice feature. Behind the scenes it's still creating all the beans you'd normally create, but in effect the namespace config amounts to a domain-specific language that makes config more convenient and intuitive.

As far as finding out about the braces, it's been far enough back in time that I can't say for sure, but I'm about 90% confident that I had to dig into the source for that little gem. :-)

On your UserDao question and password encoder questions, I agree with you that DRY applies here. What I would do in the case you describe is have three separate bean config files:

  1. an applicationContext.xml for high-reuse object like the UserDao
  2. an applicationContext-security.xml for security objects so you can take advantage of the XML default namespace feature (so you don't have to repeat the "security:" prefix everywhere, and
  3. a main-servlet.xml (or whatever you want to call it) for your web config. The web config will be able to see your applicationContext.xml but not vice versa.

Just make sure you load the app configs from the context loader instead of from the DispatcherServlet.

By Willie Wheeler on Oct 27, 2009 at 11:48 AM PDT

@Willie: I really appreciate the immediate response! Previous to reading it I had arrived at this solution:

  1. applicationContext.xml (basically empty)
  2. commonBeans.xml (userDao and a couple of other beans)
  3. applicationContext-security.xml (import on commonBeans.xml followed by security configs)
  4. dispatcher-servlet.xml (import on commonBeans.xml followed by servlet configs)

This solution was born out of my lack of knowledge and assumptions of the contexts and configuration files. I had figured that each xml file might only be able to reference beans known to its file. I was also unsure about the hierarchy of the contexts.

Obviously I was worried about my "solution" because of the duplication of beans in memory and this was set to grow because security and servlet both need message sources from i18n, etc).

The bit in your response about the web config being able to see the applicationContext.xml was a revelation. The common stuff is in applicationContext.xml and it all works very well.

I know you must be very busy with books, blogs, and your own development so thanks again!

PUK

By PUK on Nov 1, 2009 at 2:04 AM PST

Post a comment

Your name:
Your e-mail address (won't be displayed):
Your web site (optional):
example: www.xyz.com
Your comment:
Preview:
By You
Please help us reduce comment spam:
Spring Annotations RefCard
Check out the new DZone Spring Annotations Refcard by Craig Walls!

What's New?

2009-08-30 - Check out my two-part series on DZone: Spring Integration: A Hands-On Tutorial.
2009-03-25 - My new article Getting Started with Spring Batch 2.0 is available on DZone.
Home | Consulting | Tech Articles | Mailing List | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.