Spring Security - неверный токен CSRF при выходе из системы - PullRequest
1 голос
/ 11 июня 2019

У меня есть приложение, которое использует шаблоны 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. Я думаю, что решение будет как-то исключать эти скрипты заголовков и ссылки из аутентификации.

...