Spring安全方法无法确定模式是MVC还是不是Spring Boot应用程序异常

Ron*_*dey 30 java eclipse backend spring-security spring-boot

当我尝试运行应用程序时,它无法启动并抛出此异常。

该方法无法判断这些模式是否是 Spring MVC 模式。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher); 否则,请使用 requestMatchers(AntPathRequestMatcher)。

我是 Spring Security 的新手。请帮我解决这个错误。

这是我的 spring 安全配置类

package com.ronit.SpringSecurityTutorial.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
@Configuration
public class SecurityConfiguration {

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

    @Bean
    AuthenticationManager authManager(UserDetailsService detailsService) {
        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
        daoProvider.setUserDetailsService(detailsService);
        return new ProviderManager(daoProvider);
    }

    @SuppressWarnings("removal")
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.csrf(csrf -> csrf.disable()).authorizeHttpRequests(auth -> {
            auth.anyRequest().authenticated();
            auth.requestMatchers("/auth/**").permitAll();
            auth.anyRequest().authenticated();
        }).httpBasic().and().build();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 Spring Boot 应用程序

package com.ronit.SpringSecurityTutorial;

import java.util.HashSet;
import java.util.Set;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.ronit.SpringSecurityTutorial.models.ApplicationUser;
import com.ronit.SpringSecurityTutorial.models.Role;
import com.ronit.SpringSecurityTutorial.repository.RoleRepository;
import com.ronit.SpringSecurityTutorial.repository.UserRepository;

@SpringBootApplication
public class SpringSecurityTutorialApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityTutorialApplication.class,args);
    }

    @Bean
    CommandLineRunner run(RoleRepository roleRepository, UserRepository userRepository,
            PasswordEncoder passwordEncoder) {
        return args -> {
            if (roleRepository.findByAuthority("ADMIN").isPresent())
                return;
            Role adminRole = roleRepository.save(new Role("ADMIN"));
            roleRepository.save(new Role("USER"));

            Set<Role> roles = new HashSet<>();
            roles.add(adminRole);
            ApplicationUser admin = new 
            ApplicationUser(1, "Admin", passwordEncoder.encode("Password"), roles);
            userRepository.save(admin);
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

这些是 pom.xml 中的依赖项

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)

application.properties 文件中没有与安全相关的配置。

我在 Google 上搜索了这个并找到了一些 Stack Overflow 页面,但没有一个使用与我的配置类似的配置。

我看了一个在线教程并做了这个。我正确地执行了每个步骤,但我的配置不起作用。

该应用程序立即停止并终止。

我在我的应用程序中使用 Spring Boot 3 和 Spring Security 6。

小智 29

由于漏洞CVE-2023-34035而发生迁移。

如果您收到如下错误:

该方法无法判断这些模式是否是 Spring MVC 模式。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher); 否则,请使用 requestMatchers(AntPathRequestMatcher).

您应该使用完整的 RequestMatcher

例如,如果应用程序将 Servlet 部署到 /my-servlet/* 并授权该流量,如下所示:

@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();
}
Run Code Online (Sandbox Code Playgroud)

那么,应用程序应该执行以下操作:

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();
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请阅读 Spring 提供的存储库:cve-2023-34035-mitigations


Rag*_*ghu 14

目前,https://spring.io/security/cve-2023-34035推荐了两个选项

第一个选项:
在 tomcat 中做了一个非常简单的小型 poc war Web 应用程序。调试了这个方法 -

org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(HttpMethod方法,字符串...模式)

研究了https://spring.io/security/cve-2023-34035

就在上述方法中的以下几行之前,我检查了注册对象中的内容。

Assert.isTrue(registrations.size() == 1, "此方法无法判断这些模式是否是 Spring MVC 模式。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher);否则,请使用 requestMatchers( AntPathRequestMatcher).");

发现它是注册的

org.apache.catalina.servlets.DefaultServlet against "default"
org.apache.jasper.servlet.JspServlet against "jsp"
org.springframework.web.servlet.DispatcherServlet against "dispatcher"
Run Code Online (Sandbox Code Playgroud)

https://spring.io/security/cve-2023-34035中,他们提到“有时不需要这些额外的 servlet。例如,某些 servlet 容器会添加 DispatcherServlet 有效替换的 DefaultServlet。在许多情况下,这样的 servlet 可以从容器的全局配置中删除”。

他们的意思是我们应该编辑 apache-tomcat-10.1.10\conf\web.xml。

我们应该注释掉 web.xml 中 org.apache.catalina.servlets.DefaultServlet、org.apache.jasper.servlet.JspServlet 的注册。我们还应该删除同一 web.xml 中的映射条目

对于其他 servlet 容器,我们可以考虑类似的概念。

第二个选项:
另一个选项是执行他们在“有关缓解示例,请参阅以下 Spring Security 示例应用程序和相应的差异”中建议的操作。https://spring.io/security/cve-2023-34035即遵循https://github.com/spring-projects/spring-security-samples/commit/4e3bec904a5467db28ea33e25ac9d90524b53d66

换句话说,他们给出的例子是 Replace :

    .requestMatchers("/login", "/resources/**").permitAll()   
Run Code Online (Sandbox Code Playgroud)

    .requestMatchers(mvc.pattern("/login"),
         mvc.pattern("/resources/**")).permitAll()  
Run Code Online (Sandbox Code Playgroud)

在 Web 应用程序中,您通常会使用 MVC 匹配器,如下所示。您还可以使用 ant 匹配器 - 使用 ant 匹配器有一点风险,如此处所述 - antMatcher 和 mvcMatcher 之间的差异最好避免使用 ant matcher,除非您愿意在开始使用它时进行必要的测试。在复杂的场景中也可以使用正则表达式匹配器 - 仅在需要时使用它(不是在您只想解决当前问题的场景中)。

关于如何实现 mvc.pattern() 本身,这里是步骤。在某处声明一个 bean,如下所示。

@Bean
    MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
        return new MvcRequestMatcher.Builder(introspector);
    } 
Run Code Online (Sandbox Code Playgroud)

在您的安全配置中,只需像这样自动装配它:

@Autowired
    MvcRequestMatcher.Builder mvc;
Run Code Online (Sandbox Code Playgroud)

决策点:

如果您想保留原始代码,请尝试编辑服务器的(不是项目的)web.xml - 或类似的配置(如果不是 tomcat) - 而是其他一些 servlet 容器,以消除 servlet 容器中默认出现的额外 servlet。
如果您愿意更改代码,请尝试第二个选项。

另请注意:

有时,如果它的遗留代码并且您在代码中使用 DispatcherServlet 方法,您将必须消除它以使用第一个选项,否则就选择第二个选项。

希望这可以帮助

添加更多新信息

事实上,如果您进一步从 spring-boot-starter-parent:3.1.2 迁移到 spring-boot-starter-parent:3.1.3,则消息会更加清晰。它说明了问题:您的 servlet 上下文中有多个可映射 servlet:{org.apache.jasper.servlet.JspServlet=[*.jspx, *.jsp], org.springframework.web.servlet.DispatcherServlet=[/ ]}。

这就是为什么遵循https://spring.io/security/cve-2023-34035 的一个选项是禁用默认和 jsp 相关的 servlet。如果您不想更改代码但可以更改服务器配置,则很有用。

如果您选择代码更改路线,则第二个选项始终会清晰地记录下来。“对于每个 MvcRequestMatcher,调用 MvcRequestMatcher#setServletPath 来指示 servlet 路径。” 只有“否则”他们才会提到 AntMatchers

我将重复避免使用 AntMatcher,因为如果您选择第二个选项,则使用 Web 应用程序进行此迁移时会存在危险。