У меня есть приложение, которое использует шаблоны 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) после входа в систему, но только токен CSRF .html сохраняется как скрытый параметр в Thymeleaf, что приводит к ошибочной ошибке токена CSRF.
Дополнительное примечание: я заметил, что сначала загружается исходный HTML, и правильные параметры формы CSRF устанавливаются как для скрытых входных данных HTML, так и в виде файла cookie. Но затем JS, CSS и другие файлы проходят проверку подлинности CSRF, что приводит к смене маркера cookie CSRF. Я думаю, что решение будет как-то исключать эти скрипты заголовков и ссылки из аутентификации.