Which Password Encoder Should I Choose With Spring Security?
Autor
Marcus HeldDid you work on the task to integrate Spring Security in a project? If yes you probably stumbled upon the decision which PasswordEncoder
to use. I saw many developers actively researching that question and deciding on a concrete algorithm. In one project we even choose a less secure decoder - for performance reasons. Don’t. Just don’t! Don’t choose a weak encoder for performance. Actually, don’t choose at all! Let Spring handle your security.
The Problem With Security
Every few years the best practices for securing your applications changes. This is a natural behavior caused mostly by the advances we do in technology. The more and more powerful machines make certain cryptic calculation insecure. On the other hand it allows for calculating more expensive hashes in a realistic amount of time for securing the users’ password.
As an application developer it is hard to catch up with the best practices and maybe even harder to get the time to integrate them.
Let Spring solve the issue
Because of the described nature above I favor that you don’t choose an explicit encoding for your password but let Spring keep it up to date. For that purpose Spring provides the DelegatingPasswordEncoder
. You can register it by defining the PasswordEncoder
bean like that:
@Bean
fun passwordEncoder() = PasswordEncoderFactories.createDelegatingPasswordEncoder()
When looking at the implementation we can observe that Spring is encoding the information which encoder is used for encoding the password within the returned spring. An encoded password looks like that: {bcrypt}$2a$10$9GV.MwFLsu/IGW/HC.frJOEnvpYjXGxmIiXTyiUk5a6bkwgDaq6Mu
.
You can see in the beginning of the string the used algorithm is specified in the curly braces. This little addition gives spring the possibility to update the best practice of encoding a password by just introducing a new delegation. You’ll receive it for free when keeping Spring up-to-date.
But what to do with existing users?
You might notice that even with this possibility of updating the encoder old users might have a weak password hashes in place. Of course, you are unable to migrate it since you actually don’t know the password of your user. Most of the time you don’t need to act directly when a new best practice is established. So you have some time. Many users might change their password from time to time and with that they’ll also use the new encoding. If you, after some time, have serious concerns that old passwords could be exposed, you need to act out of the application. For example, you could delete all the old passwords and force the users to create a new password by using the “reset password” functionality that you have in place anyway.
But what about the salt?
Don’t worry. Springs implementation takes care of it. When looking at the example above the resulting String is consisting of 4 fields:
{bcrypt}$2a$10$9GV.MwFLsu/IGW/HC.frJOEnvpYjXGxmIiXTyiUk5a6bkwgDaq6Mu
Representation | Separated by | Meaning |
---|---|---|
{bcrypt} | { and } | The used password encoder |
$2a | $ | The used version of the bcrypt algorithm |
$10 | $ | The strength of the algorithm |
$9GV.MwFLsu/IGW/HC.frJO | The first 22 characters | The randomly generated salt |
EnvpYjXGxmIiXTyiUk5a6bkwgDaq6Mu | The rest of the string | The actual encoded password |
And the performance?
If the decoding of the password is actually a performance issue of your application then don’t decode it with every request. Introduce a JWT token which is much cheaper to evaluate and be done with it. When a user logs in he is expecting that it might take some seconds and having a strong algorithm that takes that time for calculation is a good thing, not a bad one.