Skip to content

Improve documentation about CredentialsContainer #15554

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
***** xref:servlet/authentication/passwords/jdbc.adoc[JDBC]
***** xref:servlet/authentication/passwords/user-details.adoc[UserDetails]
***** xref:servlet/authentication/passwords/credentials-container.adoc[CredentialsContainer]
***** xref:servlet/authentication/passwords/erasure.adoc[Password Erasure]
***** xref:servlet/authentication/passwords/user-details-service.adoc[UserDetailsService]
***** xref:servlet/authentication/passwords/password-encoder.adoc[PasswordEncoder]
***** xref:servlet/authentication/passwords/dao-authentication-provider.adoc[DaoAuthenticationProvider]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ image::{figures}/providermanagers-parent.png[]
By default, `ProviderManager` tries to clear any sensitive credentials information from the `Authentication` object that is returned by a successful authentication request.
This prevents information, such as passwords, being retained longer than necessary in the `HttpSession`.

[NOTE]
====
The `CredentialsContainer` interface plays a critical role in the authentication process.
It allows for the erasure of credential information once it is no longer needed, thereby enhancing security by ensuring sensitive data is not retained longer than necessary.
====

This may cause issues when you use a cache of user objects, for example, to improve performance in a stateless application.
If the `Authentication` contains a reference to an object in the cache (such as a `UserDetails` instance) and this has its credentials removed, it is no longer possible to authenticate against the cached value.
You need to take this into account if you use a cache.
Expand Down Expand Up @@ -245,7 +251,7 @@ image:{icondir}/number_2.png[] Next, the <<servlet-authentication-authentication
image:{icondir}/number_3.png[] If authentication fails, then __Failure__.

* The <<servlet-authentication-securitycontextholder>> is cleared out.
* `RememberMeServices.loginFail` is invoked.ƒ
* `RememberMeServices.loginFail` is invoked.
If remember me is not configured, this is a no-op.
See the javadoc:org.springframework.security.web.authentication.rememberme.package-summary[rememberme] package.
* `AuthenticationFailureHandler` is invoked.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
== Password Erasure

After successful authentication, it is a security best practice to erase credentials from memory to prevent them from being exposed to potential memory dump attacks.
`ProviderManager` in Spring Security supports this practice through the `eraseCredentials` method, which should be invoked after the authentication process is complete.

=== Best Practices

* *Immediate Erasure*: Credentials should be erased immediately after they are no longer needed, which minimizes the window during which the credentials are exposed in memory.
* *Automatic Erasure*: Configure `ProviderManager` to automatically erase credentials post-authentication by setting `eraseCredentialsAfterAuthentication` to `true` (the default).
* *Custom Erasure Strategies*: Implement custom erasure strategies in custom `AuthenticationManager` implementations if the default erasure behavior does not meet specific security requirements.

=== Risk Assessment

Failure to properly erase credentials can lead to several risks:

* *Memory Access Attacks*: Attackers can access raw credentials from memory through exploits like buffer overflow attacks or memory dumps.
* *Insider Threats*: Malicious insiders with access to systems could potentially extract credentials from application memory.
* *Accidental Exposure*: In multi-tenant environments, lingering credentials in memory could accidentally be exposed to other tenants.

=== Implementation

[source,java]
----
public class CustomAuthenticationManager implements AuthenticationManager {

@Override
public Authentication authenticate(Authentication authenticationRequest)
throws AuthenticationException {

Authentication authenticationResult;
// TODO: Perform authentication checks...

// Erase credentials post-check
if (authenticationResult instanceof CredentialsContainer container) {
container.eraseCredentials();
}
}

}
----

By implementing these practices, organizations can significantly enhance the security of their authentication systems by ensuring that credentials are not left exposed in system memory.
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,53 @@

javadoc:org.springframework.security.core.userdetails.UserDetails[] is returned by the xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[`UserDetailsService`].
The xref:servlet/authentication/passwords/dao-authentication-provider.adoc#servlet-authentication-daoauthenticationprovider[`DaoAuthenticationProvider`] validates the `UserDetails` and then returns an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[`Authentication`] that has a principal that is the `UserDetails` returned by the configured `UserDetailsService`.

== Credentials Management

Implementing the `CredentialsContainer` interface in classes that store user credentials, such as those extending or implementing `UserDetails`, is strongly recommended, especially in applications where user details are not cached.
This practice enhances security by ensuring that sensitive data, such as passwords, are not retained in memory longer than necessary.

[TIP]
====
In cases where user details are cached, consider creating a copy of the `UserDetails` that does not include credentials and returning the copy in the response from a custom `AuthenticationProvider` instead of the original object.
This can help prevent the cached instance containing credentials from being referenced by the rest of the application once the authentication process is complete.
====

=== When to Implement `CredentialsContainer`

Applications that do not employ caching mechanisms for `UserDetails` should particularly consider implementing `CredentialsContainer`.
This approach helps in mitigating the risk associated with retaining sensitive information in memory, which can be vulnerable to attack vectors such as memory dumps.

[source,java]
----
public class MyUserDetails implements UserDetails, CredentialsContainer {

private String username;

private String password;

// UserDetails implementation...

@Override
public void eraseCredentials() {
this.password = null; // Securely dereference the password field
}

}
----

=== Implementation Guidelines

* *Immediate Erasure*: Credentials should be erased immediately after they are no longer needed, typically post-authentication.
* *Automatic Invocation*: Ensure that `eraseCredentials()` is automatically called by your authentication framework, such as `AuthenticationManager`, once the authentication process is complete.
* *Consistency*: Apply this practice uniformly across all applications to prevent security lapses that could lead to data breaches.

=== Beyond Basic Interface Implementation

While interfaces like `CredentialsContainer` provide a framework for credential management, the practical implementation often depends on specific classes and their interactions.

For example, the `DaoAuthenticationProvider` class, adhering to the contract of `AuthenticationProvider`, does not perform credential erasure within its own `authenticate` method.
Instead, it relies on `ProviderManager`—Spring Security's default implementation of `AuthenticationManager`—to handle the erasure of credentials and other sensitive data post-authentication.
This separation emphasizes the principle that the `AuthenticationProvider` should not assume the responsibility for credentials management.

Incorporating `CredentialsContainer` into your `UserDetails` implementation aligns with security best practices, reducing potential exposure to data breaches by minimizing the lifespan of sensitive data in memory.