Bug description
When I run a load testing script that sends 150 requests/second for 10s targeting an endpoint that is protected by BASIC authentication with Spring Security, I see in JVisualVM that the CPU utilization remains mostly over 80% (even reaching peaks of 100%) and the response times increases significantly (average 302ms, p(90) 658ms, p(95) 1.1s), compared to when I run the same script targeting another endpoint in the same application that is not protected by BASIC authentication, when I see that the CPU utilization remains mostly under 10% and I get an average response time of 27ms, p(90) 46ms, p(95) 214ms.
Results of load testing the non-protected endpoint
JVisualVM Monitoring
Load Testing Tool Summary
Results of load testing the protected endpoint
JVisualVM Monitoring
Load Testing Tool Summary
To Reproduce
Basically, running a minimal application with an endpoint protected by BASIC authentication and running a load testing tool that fires 150 request/sec during 10 seconds is enough to reproduce and observe the behavior. Way more detailed information can be found on the sample provided below.
Expected behavior
When I load test the application targeting the protected endpoint, I expected CPU utilization and response times to be more similar to when I load test the application targeting the non-protected endpoint, i.e., CPU utilization around 10% and response times with average near 27ms, p(90) near 46ms, p(95) near 214ms.
Sample
I provided a minimal and reproducible sample that can be found at https://github.com/rafaelvanderlei/spring-security-loadtesting
Please let me know if more information is needed.
Comment From: rafaelvanderlei
I was wondering if there was an older version of Spring Boot that would be using an older version of Spring Security for the purpose of figuring out since which Spring Security version this behavior (100% CPU for BASIC authentication endpoint) started to happen, so I kept downgrading the Spring Boot version while keeping the rest of the application code untouched and I came up with this table:
| spring-boot-version | spring-security-web-version | result * |
|---|---|---|
| 2.5.2 | 5.5.12 | BAD |
| 2.4.8 | 5.4.7 | BAD |
| 2.3.12.RELEASE | 5.3.9.RELEASE | BAD |
| 2.2.13.RELEASE | 5.2.8.RELEASE | BAD |
| 2.1.18.RELEASE | 5.1.13.RELEASE | BAD |
| 2.1.10.RELEASE | 5.1.7.RELEASE | BAD |
| 2.1.5.RELEASE | 5.1.5.RELEASE | BAD |
| 2.1.0.RELEASE | 5.1.1.RELEASE | BAD |
| 2.0.9.RELEASE | 5.0.12.RELEASE | GOOD |
* BAD just means high CPU utilization, while GOOD means low CPU utilization
This leads us to notice that the observed behavior was introduced somewhere between Spring Security versions 5.0.12.RELEASE and 5.1.1.RELEASE.
Comment From: jzheaux
Thanks for the detailed research, @rafaelvanderlei.
This is by design. BASIC authentication requires that the password be hashed on each request in order to mitigate brute force attacks. As a general rule, password hashing for BASIC authentication should be tuned on your server to take hundreds of milliseconds per hash.
If you feel like the performance lag is not due to hashing, then please re-open with more detail, and I'd be happy to take a closer look.