Search code examples
javaspringspring-bootspring-securitybasic-authentication

Spring boot 3 - High CPU usage on basicAuth


I have a java application build on spring boot 3 and I have a simple security configuration like this:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

    private static final String[] permitMethods = new String[]{
            "/api/games/**",
            "/swagger-ui/**",
            "/v3/api-docs/**",
            "/actuator/**"
    };

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests
                                .requestMatchers(permitMethods).permitAll()
                                .anyRequest().authenticated()
                )
                .userDetailsService(userDetailsService())
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin")
                .build();
        return new CachingUserDetailsService(new InMemoryUserDetailsManager(user));
    }

}

The problem is that current application uses too much CPU over 70% while executing stress test. When I am removing .httpBasic(Customizer.withDefaults());

CPU usage goes down to 10%. I am executing stress test just with 40 parallel threads, the more parallel threads I set the more CPU usage becomes.

I am currently using spring boot 3.1.1 version but I have tried it on spring boot 3.0.0 version as well, but the result was same.

Do you have any ideas how can I minimize CPU usage with the basic authentication ?


Solution

  • the issue is simple, the cause of high cpu is in your password encoder specifically at line which is UserDetails user = User.withDefaultPasswordEncoder() now at the stage if u go to the implantation of it, you can see it uses ByCrypt algorithm for encoding passwords, and ByCrypt is expensive for CPU, since it does hashing in many iterations, you can check how bycrypt works to understand more about how it works.

    you can verify that the issue is bycrpt and not httbasic by doing following:

    define bean password encoder:

    @Bean
        public PasswordEncoder bCryptPasswordEncoder() {
            return NoOpPasswordEncoder.getInstance();
        }
    

    and here try use plain text passwords!

    also for registring users use

    UserDetails user = User.builder()
                    .username("admin")
                    .password("admin")
                    .build();
    

    now that you know the issue what can you do? you can alter some bycrypt functionalities which is available when you define BCryptPasswordEncoder as bean(check constructor). like below:

    @Bean
        public PasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder(strenght_number_that_suits_for_you);
        }
    

    or you can use faster hashing algorithm for spring security you can check implemented classes of PasswordEncoder interface

    also you can check some other related questions that might help you more like: this or this