I’m trying to understand how CSRF protection works in spring security 6.x.
I have an angular SPA that logs in the spring boot 3.0 backend with formLogin.
I have this configuration in the SecurityConfiguration:
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName("_csrf");
return http.csrf((csrf) ->
csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(requestHandler)
.ignoringRequestMatchers("/login", "/logout")
)
.cors(cors -> cors.configurationSource(corsConfigurationSourceWithCsfr()))
.authorizeHttpRequests(authRequest ->
authRequest
.requestMatchers(HttpMethod.OPTIONS)
.permitAll()
.requestMatchers("/login", "/logout")
.permitAll()
.anyRequest()
.authenticated()
)
.formLogin(formLogin -> formLogin
.successHandler((request, response, authentication) ->
response.setStatus(HttpStatus.OK.value())
)
.failureHandler((request, response, exception) ->
response.setStatus(HttpStatus.FORBIDDEN.value())
)
.loginProcessingUrl("/login")
.permitAll())
.logout(logout -> logout.logoutUrl("/logout")
.clearAuthentication(true)
.addLogoutHandler((request, response, authentication) -> {
response.setStatus(HttpStatus.OK.value());
})
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
.deleteCookies("JSESSIONID"))
.sessionManagement(sessionManager ->
sessionManager
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS))
.authenticationProvider(authProvider)
.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class)
.build();
}
And this is my CsrfTokenResponseHeaderBindingFilter
public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
if (token != null) {
response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
response.setHeader(RESPONSE_TOKEN_NAME, token.getToken());
log.info("for request: {}", request.getRequestURI());
log.info("added token {}", token.getToken());
}
filterChain.doFilter(request, response);
}
}
It is properly setting and UUID with the CSRF token in the cookies of the front end and this token is sent to the server.
This is how a request looks like:
My concern is around the fact that if i change the value of the CSRF token in the frontend cookies it still works. Is this the right way to work?
I’ve been trying all the solutions i’ve found in SO and in the official documentation.
3