У меня есть приложение, которое использует шаблоны Thymeleaf и конфигурацию Spring Boot. У меня возникла проблема с недействительным токеном CSRF при использовании некоторых конечных точек. Приложение хранит токен CSRF в файлах cookie.
На одном из шаблонов, где есть кнопка выхода, когда я не включаю никаких ссылок (таблицу стилей) и скрипты (JS) на , все работает хорошо. Но когда я включаю какие-либо заголовки или, у меня возникает проблема «Неверный токен CSRF для localhost:/logout».
Конфигурация безопасности Spring:
@Configuration
@EnableWebSecurity
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.authenticationProvider(authenticationProvider())
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf()
.csrfTokenRepository(new CookieCsrfTokenRepository())
// .disable()
.and()
.exceptionHandling()
.accessDeniedPage("/dashboard")
.and()
.httpBasic()
.disable()
.addFilterBefore(customFilter(), OAuth2LoginAuthenticationFilter.class)
.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/", "/home", "/webjars/**", "/static/**", "/css/**", "/js/**")
.permitAll()
.antMatchers("/",
"/home",
"/webjars/**",
"/error",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/logon","/login/**", "/oauth2_register/**","/register/**")
.anonymous()
.anyRequest()
.authenticated()
.and()
.formLogin()
.disable()
.logout()
.deleteCookies("access_token")
.permitAll()
.and()
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestRepository(cookieAuthorizationRequestRepository())
.authorizationRequestResolver(customAuthorizationRequestResolver())
.and()
.loginPage("/login")
.userInfoEndpoint()
.userService(customOAuth2UserService)
.and()
.successHandler(oAuth2AuthenticationSuccessHandler)
.failureHandler(oAuth2AuthenticationFailureHandler());
}
}
index.html, где я использую конечную точку по умолчанию «/logout», предоставленную Spring Security:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="'Welcome '+${user.getUsername()}+'!'"></title>
<!-- When I include the part with Bootstrap, an Invalid CSRF token error is thrown at Spring -->
<!--Bootstrap-->
<!--<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css"/>-->
<!--<link rel="stylesheet" href="/webjars/bootstrap-social/bootstrap-social.css"/>-->
<!--<link rel="stylesheet" href="/webjars/font-awesome/css/all.css"/>-->
<!--<script src="/webjars/jquery/jquery.min.js"></script>-->
<!--<script src="/webjars/popper.js/popper.min.js"></script>-->
<!--<script src="/webjars/bootstrap/js/bootstrap.min.js"></script>-->
<!--<script th:src="@{js/fade.js}"></script>-->
<!--Bootstrap-->
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="alert alert-danger" role="alert" id="backend-validation-alert" th:if="${errorMessage}">
<span th:text="${errorMessage}"></span>
<script>fade();</script>
</div>
</div>
<h1 th:text="'Welcome '+${user.getUsername()}+'!'"></h1>
<form role="form" th:action="@{/logout}" method="POST">
<div><input type="submit" value="Log out"/></div>
</form>
<form role="form" th:action="@{/user/settings/delete}" method="POST">
<div><input type="submit" value="Delete account"/></div>
</form>
</div>
</body>
</html>
Когда я отлаживал код и проверял CsrfFilter, я вижу, что в шаблоне Thymeleaf для форм POST создаются другие скрытые параметры _csrf, которые не соответствуют CSRF в файле cookie, и возникает исключение. Фильтр принимает правильное значение XSRF-TOKEN в качестве токена для проверки, но токен CSRF, хранящийся в качестве параметра в запросе, неверен и отличается.
Кто-нибудь сталкивался с подобной проблемой? Когда именно должен быть сгенерирован новый токен CSRF? Потому что в моем случае, когда я проверяю информацию о сети, я вижу, что новый токен CSRF генерируется для каждого отдельного ресурса (.js, .css, .html) после входа в систему, но только токен .html CSRF сохраняется как скрытый параметр в Thymeleaf, что приводит к ошибке Invalid CSRF token.
Дополнительное примечание: я заметил, что сначала загружается исходный html, и правильные параметры формы CSRF устанавливаются как для скрытых входов HTML, так и в виде файла cookie. Но затем JS, CSS и другие файлы проходят аутентификацию CSRF, что приводит к изменению токена cookie CSRF. Я предполагаю, что решение будет включать в себя исключение этих сценариев заголовков и ссылок из аутентификации.