Thursday, July 18, 2013

Protect you users passwords in with Jasypt

As recommended by OWASP, when storing users credentials, you always should encrypt user's password in a way that protects it from being stolen. In fact, if you are saving them in clear, and once your DB has been stolen, or accessed by even your DBA, this will make all passwords compromised. Now what about a user that used the same password for your application and his bank online account?
This been said, you should encrypt these passwords. And to do it, you have one of two possibilities:
1) Encrypt the password and save it in DB. For every attempt to login, retrieve the encrypted password, decrypt it and compare it to given password.
2) When user is registering, generate a hash code for his password and save it in DB. For every attempt to login, compare the stored hash with the generated hash of given password when login happens.
Both methods are robust if using robust algorithms. But I prefer second one. In fact, using the hash codes, makes the user the only person who can know the real password value. The first one, makes it possible for application developer to guess it.
In this article we will use Jasypt library to implement both methods. Jasypt is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.

1) Transparent password encryption with Hibernate

To implement the first approach to secure passwords, Jasypt offers a very simple and transparent enryption method. To do it, just declare the following bean in your spring context:



     
          hibernateStringEncryptor
     
     
         simplepassword
     

This will create a HibernatePBEStringEncryptor object and register it with the "hibernateStringEncryptor" name. You should use a strong password to be used when encrypting your data.

Now, we only need to add Jasypt annotations to properties we want to be encrypted transparently, here is the User entity class:
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.Type;
import org.jasypt.hibernate4.type.EncryptedStringType;
@Entity
@Table(name="user_table")
@TypeDef(
        name="encryptedString", 
        typeClass=EncryptedStringType.class, 
        parameters={@Parameter(name="encryptorRegisteredName",
                               value="hibernateStringEncryptor")}
)
public class User implements Serializable{
   //properties, here, especially the password property that we want to be encrypted:

   @Type(type="encryptedString")
   private String password;

   //Getters and Setters etc...
}
And that's all you need to do, now you can save your user objects and check the password field in DB, it will be encrypted.
Now when you wish to login a user, just check password equality as follows:
@Transactional(readOnly=true)
public User loginUser(String login, String password) {
        User user = userDao.findUserByLoginOrEmail(login);
 if(user != null ){
  if(password.equals(user.getPassword() )){
   return user;
  }
 }
 return null;
}
As you can see, we are not performing any encryption operation on data. Everything is transparent.
Please notice: never and ever use the password field on a where sql(or hql or jpql) query once it's annotated with @Type(type="encryptedString"), since it will be stored as an encrypted value, and you have no mean to compare an encrypted value against it.

2) Digest (hash code) generation for passwords

Now let's see the secodn (and my preferred method) for storing passwords. First thing to do, is to create a StringDigester bean in Spring: 



Although you can just instantiate this object whenever needed, I just wanted it to be a singleton object in the whole application. Now inject it in your service class and use it to digest passwords when saving users:
@Inject
private @Named("stringDigester")StandardStringDigester digester;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void saveUser(User user){
        //Digest password and save it
 user.setPassword(digester.digest(user.getPassword()));
 userDao.save(user);
}

//Login method:
@Transactional(readOnly=true)
public User loginUser(String login, String password) {
 User user = userDao.findUserByLoginOrEmail(login);
 if(user != null ){
           //Call StandardStringDigester.matches to compare stored digest and provided password
  if(digester.matches(password, user.getPassword())){
   return user;
  }
 }
 return null;
}
And that's it, now you are sure that your passwords are stored in a safe way.

No comments:

Post a Comment