没有 csrf 或无效 csrf 的 mockmvc 发布请求没有失败

Posted

技术标签:

【中文标题】没有 csrf 或无效 csrf 的 mockmvc 发布请求没有失败【英文标题】:mockmvc post request without csrf or invalid csrf is not failing 【发布时间】:2021-09-05 22:57:39 【问题描述】:

我有一个带有 spring security 5spring boot-2.5.1 应用程序。

WebSecurityConfig 如下所示:

@Slf4j
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    private final CustomProperties customProperties;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        if (customProperties.isEnabled()) 
            log.info("authentication enabled.");
            http.authorizeRequests()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .oauth2Login()
                    .redirectionEndpoint()
                    .baseUri(customProperties.getAuthorizationResponseUri())
                    .and()
                    .userInfoEndpoint(userInfo -> userInfo.userService(new CustomOAuth2UserService()::loadUser));
         else 
            log.info("authentication disabled.");
            http.authorizeRequests()
                    .anyRequest()
                    .permitAll();
        
    

    public void configure(WebSecurity webSecurity) 
        webSecurity.ignoring()
                .antMatchers("/actuator/info", "/actuator/health/*");
    


控制器如下所示:

@Controller
@RequiredArgsConstructor
public class UserController 

    private final UserService userService;

    @PostMapping("/users")
    public @ResponseBody Mono<Map<String, String>> saveUsers(@RequestBody List<UserDto> userDtos) 
        return userService.saveUser(userDtos);
    

上述控制器对应的JUnit:

@AutoConfigureMockMvc
@WebMvcTest(UserController.class)
class UserControllerTest 

    @Autowired
    private MockMvc mockMvc;
    
    @MockBean
    private  UserService userService;
    
        @SneakyThrows
        @Test
        @WithMockTestUser
        void shouldSaveUsers() 
            var userDtos = "...";
    
            mockMvc.perform(post("/users")
                    .contentType(APPLICATION_JSON)
                    .content(userDtos))
                    .andDo(print())
                    .andExpect(status().isOk());
        
    

JUnit 没有 CSRF 的状态为 OK 而不是禁止的请求。 如果我调试,我可以看到,如果 csrf() 不包括在内,则不会生成令牌并分配给请求。但是,请求仍然通过。理想情况下,它应该抛出禁止的请求访问。

即使使用 csrf(),我也可以看到生成令牌并分配给参数。

在这两种情况下,我都没有看到任何地方正在验证 POST 请求是否包含 mockmvc 令牌。

mockmvc 是否需要任何额外的配置来验证 POST 请求是否包含 CSRF

【问题讨论】:

【参考方案1】:

您需要使用SecurityMockMvcConfigurers.springSecurity() 构建MockMvc,而不是自动配置MockMvc。 这会将名为“springSecurityFilterChain”的 Spring Bean 添加为过滤器,并确保每个请求都使用 TestSecurityContextHolder

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

@Before
public void setup() 
    this.mockMvc = MockMvcBuilders
            .webAppContextSetup(this.context)
            .apply(springSecurity())
            .build();


【讨论】:

我尝试了建议的方法。但是,如果添加或不添加 csrf,仍然不会调用 CsrfFilter。但是,我可以看到即使添加或不添加 csrf,仍然会调用 CsrfConfigurer。因此,post 请求仍然是成功的,而不是禁止访问 @user2800089 WithMockTestUser 看起来像什么?如果你使用内置的@WithMockUser,你会得到同样的结果吗? @WithMockTestUser 是具有安全上下文 WithMockTestUserSecurityContextFactory 的注释。我对此进行了自定义,因为身份提供者不会将主体信息作为默认 oauth2 用户返回,因此我自定义了 userinfo,这就是自定义模拟 userinfo 的原因

以上是关于没有 csrf 或无效 csrf 的 mockmvc 发布请求没有失败的主要内容,如果未能解决你的问题,请参考以下文章

在 Broadleaf 项目中 HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”

$_csrf.parameterName 和 $_csrf.token 返回 null

尝试上传时 CSRF 令牌 Spring 4 MVC 无效

停止在身份验证时重新生成/使 CSRF 无效

无法解释无效的 CSRF 令牌 rails api

Symfony2:记住我身份验证时无效的 CSRF 令牌