Spring Boot 3 – 基本认证的高CPU使用率

huangapple go评论85阅读模式
英文:

Spring boot 3 - High CPU usage on basicAuth

问题

我有一个基于Spring Boot 3构建的Java应用程序,其中有一个简单的安全配置如下:

@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));
    }

}

问题是,当前应用程序在执行压力测试时CPU使用率过高,超过70%。
当我移除.httpBasic(Customizer.withDefaults());时,CPU使用率下降到10%。
我只是用40个并行线程执行压力测试,设置更多并行线程后,CPU使用率变得更高。

我目前使用的是Spring Boot 3.1.1版本,但我也尝试过Spring Boot 3.0.0版本,但结果是相同的。

您有任何想法如何通过基本身份验证来最小化CPU使用率?

英文:

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 ?

答案1

得分: 1

问题很简单,高CPU使用率的原因在于您的密码编码器,具体位于这一行代码:UserDetails user = User.withDefaultPasswordEncoder()。现在,如果您查看它的实现,您会发现它使用了ByCrypt算法来对密码进行编码,而ByCrypt算法对CPU来说是昂贵的,因为它进行了多次迭代的哈希运算,您可以查看ByCrypt的工作原理来更了解它的工作方式。

您可以通过以下方式验证问题是否是ByCrypt而不是HTTP Basic导致的:

定义密码编码器bean:

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

在这里尝试使用明文密码!

还有,在注册用户时使用以下方式:

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

既然您知道了问题,您可以做什么?
您可以修改一些ByCrypt功能,这些功能在您将BCryptPasswordEncoder定义为bean时可用(检查构造函数)。可以像下面这样:

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

或者
您可以使用Spring Security的更快的哈希算法,可以查看PasswordEncoder接口的实现类。

此外,您可以查看一些其他相关问题,这些问题可能会更有帮助,比如:
这个 或者 这个

英文:

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

huangapple
  • 本文由 发表于 2023年7月17日 21:17:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76704872.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定