This repo is a set of samples to demonstrate the arrangements wherein applications may be vulnerable to CVE-2023-34035.
An application is vulnerable when all of the following are true:
Spring MVC is on the classpath
DispatcherServlet
and at least one other servlet are mapped; one of them having a path-based servlet mapping (for example, /path/**
)
The application uses requestMatchers(String)
to refer to endpoints whose servlet mapping is of the form /path/**
There are a set of samples that use Spring Boot and a set that do not.
The samples that contain failing tests are vulnerable to CVE-2023-34035. The samples whose tests pass are not vulnerable.
In all cases, each of these samples contains the same mitigation error from Spring Security, though note that such a mitigation is temporary in many circumstances, pending the next maintenance release.
This sample represents a vulnerable application where DispatcherServlet
is deployed to /mvc/*
instead of the default /
.
It is vulnerable since Spring MVC is on the classpath, DispatcherServlet
and at least one other servlet is mapped — one of them with a non-root, path-based servlet mapping (in this case, DispatcherServlet
), and the application uses requestMatchers(String)
to secure those endpoints.
This sample represents a safe application where DispatcherServlet
is deployed to /
(the default).
It is not vulnerable. While Spring MVC is on the classpath and DispatcherServlet
is in use, it is deployed to /
and there are no non-root, path-based servlet mappings.
This sample represents a vulnerable application where DispatcherServlet
is deployed as well as a custom servlet MyServlet
.
It is vulnerable since Spring MVC is on the classpath, DispatcherServlet
and at least one other servlet is mapped — one of them with a non-root, path-based servlet mapping (in this case, MyServlet
), and the application uses requestMatchers(String)
to secure those endpoints.
This sample represents a safe application where DispatcherServlet
is deployed to /
(the default).
It is not vulnerable. While Spring MVC is on the classpath and DispatcherServlet
is in use, it is deployed to /
and there are no non-root, path-based servlet mappings.
This sample represents a vulnerable application where DispatcherServlet
is deployed as well as a custom servlet MyServlet
.
It is vulnerable since Spring MVC is on the classpath, DispatcherServlet
and at least one other servlet is mapped — one of them with a non-root, path-based servlet mapping (in this case, one of the two DispatcherServlet
s), and the application uses requestMatchers(String)
to secure those endpoints.
This sample represents a vulnerable application where DispatcherServlet
is deployed to /mvc/*
instead of the default /
.
It is vulnerable since Spring MVC is on the classpath, DispatcherServlet
and at least one other servlet is mapped — one of them with a non-root, path-based servlet mapping (in this case, DispatcherServlet
), and the application uses requestMatchers(String)
to secure those endpoints.
This sample represents a safe application where DispatcherServlet
is deployed to /
(the default).
It is not vulnerable. While Spring MVC is on the classpath and DispatcherServlet
is in use, it is deployed to /
and there are no non-root, path-based servlet mappings.
This sample represents a vulnerable application where DispatcherServlet
is deployed as well as a custom servlet MyServlet
.
It is vulnerable since Spring MVC is on the classpath, DispatcherServlet
and at least one other servlet is mapped — one of them with a non-root, path-based servlet mapping (in this case, MyServlet
), and the application uses requestMatchers(String)
to secure those endpoints.
This sample represents a safe application where DispatcherServlet
is deployed to /
(the default).
It is not vulnerable. While Spring MVC is on the classpath and DispatcherServlet
is in use, it is deployed to /
and there are no non-root, path-based servlet mappings.
This sample represents a safe application where DispatcherServlet
is deployed to /
(the default).
It is not vulnerable. While Spring MVC is on the classpath and DispatcherServlet
is in use, it is deployed to /
and there are no non-root, path-based servlet mappings.
In the event that you get an error like the following:
This method cannot decide whether these patterns are Spring MVC patterns or not.
If this endpoint is a Spring MVC endpoint, please use `requestMatchers(MvcRequestMatcher)`;
otherwise, please use `requestMatchers(AntPathRequestMatcher)`.
you should follow it.
Note
|
The 5.8.5 , 6.0.5 , 6.1.2 , and 6.2.0-M1 versions of Spring Security have some false positives.
Now that in many cases the following is temporary, pending the release of 5.8.6 , 6.0.6 , 6.1.3 , and 6.2.0-M2 .
|
As alluded to by the error message, the primary mitigation is to use a complete RequestMatcher
.
This is so that the servlet mapping can be more clearly accounted for.
For example, if an application has a servlet deployed to /my-servlet/*
and is authorizing that traffic like so:
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/my-servlet/**").hasRole("USER")
.requestMatchers("/spring-mvc-controller/**").hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
then, the application should instead do:
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(antMatcher("/my-servlet/*")).hasRole("USER")
.requestMatchers(mvc.pattern("/spring-mvc-controller/**")).hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
Or, if DispatcherServlet
is deployed to a different path, like /spring-mvc/*
, then instead of:
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/spring-mvc/controller/**")).hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
an application should do:
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(mvc.pattern("/controller/**")).hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
Separating the servlet path when constructing an MvcRequestMatcher
is important to ensure that the request is correctly matched.
In this repo, there is a branch for each minor release of Spring Security. On that branch, there is a commit for each affected sample with the needed mitigation.
For example, on the 5.8.x
branch, there are eight commits to repair the eight samples that require mitigation.
When 5.8.6
, 6.0.6
, 6.1.3
, and 6.2.0-M2
are released, additional changes will be made to those branches so the best-practice mitigation is clear.