-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Improve CVE-2023-34035 detection #13568
Comments
So after digging a bit deeper I have found a workaround The following example:
Would need to be turned into:
But again. This is a breaking change one doesn't expect in a patch release. Also, the Should the assertion stick for whatever valid reason or turned into a log statement, the message is somewhat confusing because there are no methods inside Having all of that said, I don't think using the In summary: I think the assertion should just be removed and also not turned into a log message, warning people to migrate to something else. Cheers |
https://spring.io/security/cve-2023-34035 explains well what has changed and how to fix this error, however I agree that a patch release should not introduce breaking changes like this. |
Oh, I've missed that announcement. Thanks for sharing.... But even then:
Which is the case in the reproducer app I shared. I wouldn't expect a breaking change for those applications. |
So, if the app is only uses MVC we can safely wait for proper non-breaking change fix? |
Hi, what is the Satus of this issue? i faced the same Problem! Must i realy use Edit: With 3.1.1 Its working without MVCRequestMatcher.Builder. The Problem appears only on 3.1.2 |
You can use the constructor |
To make matters worse, |
But this seems does not work if deploy as a war in Tomcat. |
Resolved, I have another line:
|
Thanks, Everyone, for reaching out. We avoid breaking changes in maintenance releases; however, as happens with CVEs at times, it's necessary to introduce one. Thank you for your patience during this upgrade. As has already been stated, there are examples in the CVE report for how to make the appropriate changes. I've also added a blog post to bring more visibility to the needed changes.
I do not believe this can be downgraded to a warning message, given that |
So with an out-of-the-box embedded Undertow setup which provides a "default" |
I think |
The default servlet in my case has no path mapping ( |
I wonder if we could provide a better migration path with the following. --- a/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
@@ -39,6 +39,7 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
@@ -201,7 +202,11 @@ public abstract class AbstractRequestMatcherRegistry<C> {
if (!hasDispatcherServlet(registrations)) {
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
}
- Assert.isTrue(registrations.size() == 1,
+ // Filter out "empty" servlets without any mappings
+ List<? extends ServletRegistration> servletRegistrations = registrations.values().stream()
+ .filter(registration -> !CollectionUtils.isEmpty(registration.getMappings()))
+ .toList();
+ Assert.isTrue(servletRegistrations.size() == 1,
"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).");
return requestMatchers(createMvcMatchers(method, patterns).toArray(new RequestMatcher[0]));
} In case you think this could be a (part of the) solution @jzheaux I'll provide a PR. At least with this, some (certainly not all) applications unaffected by the security issue don't have a requirement on changing their code. I do share the sentiment that these applications should not require a change - anything other than the version number. I also still have the opinion that the former In my particular case, I'm also not talking about applications under my (full) control, but me providing internal libraries that need to impose breaking changes to our internal customers now as well. For something that they are unaffected by, really. |
@dreis2211, @albertus82, thanks for the ideas and perspective. Based on your feedback, I've updated the Mitigation section in the security advisory to suggest that individuals remove unneeded servlets from their application runtime. We don't want to deprecate I don't think that the method can be smarter than it is at this point since servlet containers configure and expose default servlets differently (some do have mappings, for example). Also, some containers add other servlets by default like Where I lean is in providing a simpler way to recover when this situation comes up.
I can understand the position of frustration that you are coming from. Many folks just did a major version upgrade and that can be tricky on its own. That said, when it's revealed that a default usage of Spring Security is insecure, it's important to respond quickly and clearly so that we can all move to a more secure place. Given that, the happy medium is to make it easier to recover. The current recovery options are not ideal, so let's work on that.
This could be, though I think this more generally speaks to a desire to simplify the mitigation. IOW, so long as it is easy to do the secure thing, it shouldn't matter so much when a developer finds out the thing they first did was insecure. One approach that I am liking right now is to introduce a builder that simplifies creating the right request matcher. I'll work on vetting the pros and cons of all the ideas shared so far. In the meantime, folks are welcome to use the following builder: @Component
public class RequestMatcherBuilder {
private final HandlerMappingIntrospector introspector;
private final String servletPath;
@Autowired
public RequestMatcherBuilder(HandlerMappingIntrospector introspector) {
this(introspector, null);
}
private RequestMatcherBuilder(HandlerMappingIntrospector introspector, String servletPath) {
this.introspector = introspector;
this.servletPath = servletPath;
}
public MvcRequestMatcher[] matchers(String... patterns) {
MvcRequestMatcher[] matchers = new MvcRequestMatcher[patterns.length];
for (int index = 0; index < patterns.length; index++) {
matchers[index] = new MvcRequestMatcher(this.introspector, patterns[index]);
if (this.servletPath != null) {
matchers[index].setServletPath(this.servletPath);
}
}
return matchers;
}
public RequestMatcherBuilder servletPath(String path) {
return new RequestMatcherBuilder(this.introspector, path);
}
} Then an application can do: @Bean
SecurityFilterChain appSecurity(HttpSecurity http, RequestMatcherBuilder mvc) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(mvc.servletPath("/graphql").matchers("/**")).hasAuthority("graphql"))
.requestMatchers(mvc.matchers("/flights/**", "/user/**")).hasRole("USER")
.anyRequest().authenticated()
)
.csrf((csrf) -> csrf
.ignoringRequestMatchers(mvc.matchers("/to", "/be", "/ignored"))
)
// ...
} The majority of folks will only need the Again, I understand that breaking changes are rare for a maintenance release and that this is unexpected and painful. Thank you for your efforts to make this an easier transition. |
I see no(?) way in preventing Undertow to register its default Servlet.
I'd call my Boot application a kinda standard one with no fancy configuration using |
You can set the servlet paths in your application.properties file to point to WEB-INF and META-INF.
…________________________________
From: Anant Jagania ***@***.***>
Sent: Wednesday, August 23, 2023 1:56 PM
To: spring-projects/spring-security ***@***.***>
Cc: Subscribed ***@***.***>
Subject: Re: [spring-projects/spring-security] Improve CVE-2023-34035 detection (Issue #13568)
I am using Spring Boot 3.1.2 and Spring Security 6.1.3 and still have the same issue.
Spring registers two servlets as shown below. The Dispatcher servlet is mapped to "/".
If I disable jsp servlet then my JSP's won't be shown and it says invalid path due to "Path with WEB-INF or META-INF: "
Please advise on any workaround. There is no second servlet mapped to any path.
Caused by: java.lang.IllegalArgumentException: 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).
This is because there is more than one mappable servlet in your servlet context: {org.apache.jasper.servlet.JspServlet=[*.jspx, *.jsp], org.springframework.web.servlet.DispatcherServlet=[/]}.
—
Reply to this email directly, view it on GitHub<#13568 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/APLVTXMZLW5FHP7KGU262E3XWY743ANCNFSM6AAAAAA2RUK5AQ>.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Thanks for the reply. My understanding is setting up view resolver to WEB-INF/jsp and suffix .jsp should be enough for spring to resolve jsps. I do not see any other properties to set servlet paths to WEB-INF. The servlet path is already set to "/". Spring actually looks for jsp resources inside META-INF/resources so I tried to move my jsps inside META-INF/resources from META-INF/resources/WEB-INF . That passed the check for isInvaidPath but now it downloads the jsp on the browser rather than showing it. I do have all the necessary tomcat libraries in Classpath. |
A lot of comments, but I can not find a solution to my problem. I have this error when I deploy my WAR on JBoss. What can I do about it?
I don't know what this JSP/JSF is, we don't use it specifically. Maybe we use it under the hood, but it runs perfectly on the embedded Tomcat and only fails on JBoss. We use the default servlet path. |
@Ariel15682 |
@dari220 |
Debugging results in Version 3.1.3 (with embedded Tomcat) when using AntPathRequestMatcher
|
@Ariel15682, thank you for your solution. I had issue with H2 and it helped me.
But there is no need in @Configuration
public class SecurityConfig {
// My enpdoints start from /v1 so this pattern is ok for me
private static final String API_URL_PATTERN = "/v1/**";
@Bean
public SecurityFilterChain getSecurityFilterChain(HttpSecurity http,
HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
http.csrf(csrfConfigurer ->
csrfConfigurer.ignoringRequestMatchers(mvcMatcherBuilder.pattern(API_URL_PATTERN),
PathRequest.toH2Console()));
http.headers(headersConfigurer ->
headersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin));
http.authorizeHttpRequests(auth ->
auth
.requestMatchers(mvcMatcherBuilder.pattern(API_URL_PATTERN)).permitAll()
//This line is optional in .authenticated() case as .anyRequest().authenticated()
//would be applied for H2 path anyway
.requestMatchers(PathRequest.toH2Console()).authenticated()
.anyRequest().authenticated()
);
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
return http.build();
}
} Update 1: changed code for H2 console to work properly in browser and implemented @jzheaux recommendation. |
We need to use a MvcRequestMatcher now to avoid problems if multiple servlets are deployed (in case of H2 for example). spring-projects/spring-security#13568 (comment)
@plantexchen I'm sorry that you are having trouble. You mentioned that you tested things with JBoss and embedded Tomcat. Can you describe in what circumstances you are using each (e.g. embedded for development, JBoss for production)? |
@MarkvanOsch I'm not sure I can comment on whether you need the second DispatcherServlet. If you indeed do not, then yes, you are welcome to remove it and the error should be resolved. However, if you do need both, then please see this sample and specifically this commit log for an example of how to specify request matchers correctly.
Without more understanding of your situation, I'm a little surprised to hear that you have this dependency but don't need the dispatcher servlet, as it's a core part of the web service module. But not being the expert in that case, I'd refer you to the web services team. |
In WebMvcConfigurer ` @OverRide
The class 'InternalResourceViewResolver' states I'm INTERNAL and I'm VIEW Resolver. Complete Process:
How would You solve this? |
Hi, @dari220, I'm sorry that you are having trouble. I'd prefer to keep the focus in this thread on how to adapt the |
@DenisKorolev, @Ariel15682, and others using H2 Console, you may be able to simplify things by using Spring Boot's H2 Console http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(PathRequest.toH2Console()).permitAll()
// ...
)
// ... |
Hi , @jzheaux, thank You for the hint -> 'thats not the subject of requestMatchers'. I was sure it is. Add this line to your security filter chain. |
Hi @MarkvanOsch, In our application we also use spring-boot-starter-web for our rest interface and spring-boot-starter-web-services exclusively to consume a soap web service. According to github, the web services starter contains two auto-configurations:
We only need the latter autoconfiuration for our client operations. That's why I added the following annotation:
Maybe this is the right way for your application too. |
@Pax90 Hi David, thanks! I can confirm that this solution works for our project with the same setup as yours. 👌 |
Given that #13850 and #13562 were just merged, I'd like to post an update here and a request for folks affected to try out the latest snapshot. In summary, the following changes were made:
If you have .authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/my/controller/**").hasRole("USER")
.requestMatchers("/admin/controller/**").hasRole("ADMIN")
.requestMatchers("/graphql").authenticated()
) Because In the latest 6.2 snapshot, you can now do this: .authorizeHttpRequests((authorize) -> authorize
.forServletPattern("/mvc/*", (mvc) -> mvc
.requestMatchers("/my/controller/**").hasRole("USER")
.requestMatchers("/admin/controller/**").hasRole("ADMIN")
)
.forServletPattern("/graphql", (graphql) -> graphql
.anyRequest().authenticated()
)
) This gives Spring Security enough information now to ensure that the correct request matcher instance is created since it now also has the missing Note that while I recommend always specifying the servlet path in this way if Please see more details in the SNAPSHOT reference. I'm currently looking into what aspects of #13850 and #13562 can be safely backported to 5.8, 6.0, and 6.1 and will report that progress on those tickets. |
…wrappers Also fixed encountered issues: * spring-projects/spring-security#13568 * gradle/gradle#20132 * google/ksp#1445 `BeeFetchedTest` now uses updated DGS generate client V2 API.
Hi all, To limit the usage of verbatim strings in code and to prevent code vs application.yml configuration mismatch, we could benefit from an injectable bean providing the spring-boot well-known paths (root, h2-console, templates, static) as they are currently configured in the spring context. As an example, when I first tried the new solution proposed above by @jzheaux I received an error: "The given pattern /h2-console/** doesn't seem to match any configured servlets" because I had typed: I would have loved to have something like the public SecurityFilterChain filterChain(HttpSecurity http, SpringPaths paths) throws Exception {
http.authorizeHttpRequests((authorize) -> authorize
.forServletPattern(paths.mvc(), mvc -> mvc ... )
.forServletPattern(paths.h2Console(), h2 -> h2 ... )
.forServletPattern(paths.statics(), static -> static ... )
); regards. |
Hi everyone, Thank you all for the discussion in this issue and explaining the situation. There are a couple of things I would like to provide feedback on: So far the discussion has been around using relative paths with multiple servlets when none of them are set as the root. Would it make sense to have an additional check added to http.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/mvc/my/controller/**").hasRole("USER")
.requestMatchers("/mvc/admin/controller/**").hasRole("ADMIN")
.requestMatchers("/graphql").authenticated()
) Secondly, I noticed that the Lastly, we use separate |
Thanks, @zoaked, for this observation. The concern is that there is no way for Spring Security to know which you are doing (since both are just strings) and thus there is no way to use that information to allow or reject the configuration. At the very least, a new method with a new method parameter is needed, e.g. .servletPatternMatchers("/mvc", "/my/controller/**").hasRole("USER")
.servletPatternMatchers("/mvc", "/admin/controller/**").hasRole("ADMIN")
.servletPatterntMatchers("/graphql").authenticated() so that the servlet path value is clear. And an early version of the DSL changes did precisely this. The reason for moving it into a separate DSL altogether is it makes it clear that what you are doing is configuring endpoints by-servlet, not just providing additional request matching detail.
public SecurityFilterChain filterChain(HttpSecurity http, SpringPaths paths) throws Exception {
http.authorizeHttpRequests((authorize) -> authorize
.forServletPattern(paths.mvc(), mvc -> mvc ... )
.forServletPattern(paths.h2Console(), h2 -> h2 ... )
.forServletPattern(paths.statics(), static -> static ... )
); Thanks, @zartc, I think this is a good idea; as you said, the precise servlet pattern is not always apparent since most servlets are auto-configured. |
Based on some feedback from #13794, we've decided to hold off on this new DSL for just a bit longer. All the enhanced validation is still scheduled for the next point releases, including 6.2.0. As a reminder, the validation enhancements (#13666, #13667, and #13850) are made so that Spring Security only errors when both of these are true:
|
i think not a good idea, always error in war |
@1057105012 can you please provide more detail, hopefully in the form of a minimal GitHub project, about your arrangement? I don't believe it's correct that it always errors in a war setup, so I'll need more information to see what will help your situation best. |
⚡ UPDATE ⚡: A proposed solution is available in the latest 6.2 snapshot build. Please see this comment for details. I would love your feedback.
UPDATE: Thanks again, @dreis2211 for the report.
As reported, there are some false positives with the validation put in place in response to CVE-2023-34035. A fix was released in 5.8.6, 6.0.6, and 6.1.3 to improve the validation.
In all cases, a new repo is now available with several more examples across all affected maintenance releases of Spring Security. The readme indicates which samples are vulnerable and which aren't.
The original post follows:
Hi,
with the work on #13551 a regression has been introduced that prevents the startup of applications under certain (unfortunately not very uncommon) circumstances.
There are multiple already mentioned in the issue, another one I'm facing is that Undertow always registers a default servlet even if there are no mappings leading to two registrations being returned here:
spring-security/config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java
Line 322 in df239b6
For simpler reproduction, simply check out https://github.com/dreis2211/spring-security-13568 and try to startup the app.
It should yield a stacktrace showing this:
I think the assertion needs to be reverted for the time being and revisited at a later point. Or making it a warning log instead of the assertion, should this be really a case that you want to prevent in the future with a proper non-patch release.
Cheers,
Christoph
The text was updated successfully, but these errors were encountered: