Skip to content

Hidden cost of password upgrade #8498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jmisur opened this issue May 6, 2020 · 5 comments
Closed

Hidden cost of password upgrade #8498

jmisur opened this issue May 6, 2020 · 5 comments
Assignees
Labels
status: duplicate A duplicate of another issue

Comments

@jmisur
Copy link

jmisur commented May 6, 2020

Context

So DelegatingPasswordEncoder decided to upgrade password encoding. This is arguably a reasonable decision, however it's not required every time and it has a hidden cost.

For example, if you have a simple http basic in-memory authentication for use between internal services, where password is stored in a secure cloud storage attached to the service, you might not need such upgrade behavior.

DelegatingPasswordEncoder however criples the performance of the service by upgrading the password to bcrypt after first successful call (in-memory in this case).
See the attached performance analysis breakdown, it's cost is overwhelming for a simple CRUD service.

Possible solution
Keep NoOpPasswordEncoder (it's deprecated) and/or add some property to prevent an encoding upgrade.
Also documenting this would help people debugging performance issues.

Screenshot 2020-05-06 at 23 55 10

@jmisur jmisur added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels May 6, 2020
@rwinch
Copy link
Member

rwinch commented May 8, 2020

Thanks for the report.

This is arguably a reasonable decision, however it's not required every time and it has a hidden cost.

The password should only upgraded once since the underlying implementation is consulted if passwords should be upgraded or not. So it should not upgrade every time.

DelegatingPasswordEncoder however criples the performance of the service by upgrading the password to bcrypt after first successful call (in-memory in this case).
See the attached performance analysis breakdown, it's cost is overwhelming for a simple CRUD service.

I believe we did a good job on documenting the performance impact of validating properly encoded passwords and that long term credentials (i.e. passwords) should be exchanged for short term ones (i.e. session, OAuth token, etc), but we need to do better with the fact that passwords may be upgraded and how that works. I created gh-8505 to address this.

Keep NoOpPasswordEncoder (it's deprecated) and/or add some property to prevent an encoding upgrade.

It is only deprecated because it is considered insecure and there are no plans to remove it. This means you can use NoOpPasswordEncoder without worrying about it being removed. However, I must emphasize that it is NOT SECURE.

I created gh-8506 to update our Javadoc to make it clear that it is not going to be removed. Would you be interested in submitting a Pull Request for this?

With the above linked issues, I believe this addresses your concerns. Can you please confirm or let me know what is still missing?

@rwinch rwinch added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels May 8, 2020
@jmisur
Copy link
Author

jmisur commented May 12, 2020

Thank you, a better documentation will help a lot. This can be closed.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 12, 2020
@rwinch rwinch self-assigned this May 13, 2020
@rwinch rwinch added status: duplicate A duplicate of another issue and removed status: feedback-provided Feedback has been provided type: enhancement A general enhancement labels May 13, 2020
@rwinch
Copy link
Member

rwinch commented May 13, 2020

Thanks for the feedback @jmisur

Closing in favor of the issues that were created based on the feedback.

@ahahu
Copy link

ahahu commented Oct 29, 2020

The password should only upgraded once since the underlying implementation is consulted if passwords should be upgraded or not. So it should not upgrade every time.

Just experienced the very same issue and would like to note that the above comment seems a bit misleading: while the upgrade is performed only once, the resulting performance impact happens on every of the following authentications.
So in a very typical scenario with http basic in-memory authentication based on "{noop}" encoded passwords for internal service communication, this creates a really heavy performance penalty.

While I applaud the security thinking, I also consider this is a regression.

@rwinch
Copy link
Member

rwinch commented Oct 29, 2020

@ahahu As mentioned previously, you can expose a NoOpPasswordEncoder Bean to go back to the previous behavior. The only implementation of UserDetailsPasswordService is InMemoryUserDetailsManager so the upgraded password is not persisted. This means that restarting your application will revert to using the previous encoding as well. In the end, this is a much better default as it helps ensure passwords are secure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

4 participants