728x90
반응형

Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN' 에러

스프링 시큐리티에서 CSRF(Cross-site Request Forgery) 보안 기능을 사용할 때 발생하는 에러

보안 기능이 동작하지 않아 발생하거나 설정이 잘못되어 발생할 수 있음

 


에러 발생 원인

이 에러는 주로 CSRF 토큰 값이 전달되지 않았거나, 전달된 토큰 값이 유효하지 않을 때 발생함

스프링 시큐리티에서는 CSRF 보안 기능을 사용할 때, 사용자의 세션에 저장된 CSRF 토큰 값과 요청으로 전달된 CSRF 토큰 값을 비교하여 일치하지 않으면 이 에러를 발생시킴

 


해결 방법

CSRF 보안 기능 해제

가장 간단한 해결책은 CSRF 보안 기능 해제

이 방법은 보안 취약점을 유발할 수 있기에 권장되는 방법은 아니지만, 개발 단계에서 CSRF 보안 기능을 잠시 해제하여 개발 편의성을 높이기 위해 사용하기에는 괜찮을 수 있음

예시

@Configuration
@EnableWebSecurity
public class SecurityConfig implements WebSecurityConfigurer<WebSecurity> {

    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/user/**").hasRole("USER")
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .logout()
            .permitAll()
            .and()
            .csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
            .usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username = ?")
            .authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username = ?");
    }

}

 


CSRF 토큰 값을 전달하기


CSRF 토큰 값을 전달하는 방법
- 폼(form) 데이터에서 CSRF 토큰 값을 함께 전달하는 방법
- AJAX 요청에서 CSRF 토큰 값을 HTTP 헤더(X-CSRF-TOKEN)에 포함하여 전달하는 방법
- CSRF 토큰 값을 JavaScript로 읽어와 요청 시 함께 전달하는 방법


이 중에서 가장 일반적인 방법은 폼 데이터에서 CSRF 토큰 값을 함께 전달하는 방법

스프링 시큐리티에서는 CSRF 토큰 값을 함께 전달해야 함

그렇지 않으면 'null' 에러가 발생할 수 있음

 


폼(form) 데이터에서 CSRF 토큰 값을 함께 전달하는 방법 👇

<form method="post" th:action="@{/user}">
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
    <!-- other form fields -->
    <button type="submit">Submit</button>
</form>

 

AJAX 요청에서 CSRF 토큰 값을 HTTP 헤더(X-CSRF-TOKEN)에 포함하여 전달하는 방법  👇

$(document).ready(function() {
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
 
    $(document).ajaxSend(function(e, xhr, options) {
        xhr.setRequestHeader(header, token);
    });
});

 

CSRF 토큰 값을 JavaScript로 읽어와 요청 시 함께 전달하는 방법 👇

function sendCsrfToken(xhr, settings) {
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    xhr.setRequestHeader(header, token);
}
 
$.ajaxSetup({
    beforeSend: sendCsrfToken
});
반응형
복사했습니다!