Spring Boot + Security - Can't upload file (Multipart) when CSRF is enabled

spring boot wiki
spring boot version
spring boot tutorialspoint
spring boot-starter
spring boot project
spring-boot-maven
spring boot java
spring boot interview questions

I want to upload files from my angularJS client. I have enabled CSRF protection and it works fine except when i try to upload a file, where i get a 403 error:

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

But the token is in the request headers and is correct! When i disable the CSRF protection i can upload the files without any problem.

The CSRF protection works fine besides that.

Here is my current configuration:

SecurityConfiguration.java

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityUserDetailsService securityUserDetailsService;
    @Autowired
    private AuthFailureHandler authFailureHandler;
    @Autowired
    private AjaxAuthSuccessHandler ajaxAuthSuccessHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .exceptionHandling()
                .authenticationEntryPoint(authFailureHandler)
                .and()
                .authorizeRequests()
                .antMatchers(
                        "/",
                        "/index.html",
                        "/styles/**",
                        "/bower_components/**",
                        "/scripts/**"
                ).permitAll().anyRequest()
                .authenticated()
                .and().formLogin().loginPage("/login").permitAll()
                .and().logout().logoutUrl("/logout").logoutSuccessHandler(ajaxAuthSuccessHandler).permitAll()
                .and().httpBasic()
                .and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
                .csrf().csrfTokenRepository(csrfTokenRepository());
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(securityUserDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

}

CsrfHeaderFilter.java

public class CsrfHeaderFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
        if (csrf != null) {
            Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
            String token = csrf.getToken();
            if (cookie == null || token != null && !token.equals(cookie.getValue())) {
                cookie = new Cookie("XSRF-TOKEN", token);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
        filterChain.doFilter(request, response);
    }
}

And last i have added a SecurityWebApplicationInitializer as pointed here.

SecurityWebApplicationInitializer.java

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }

}

What am i doing wrong?

Update: i added this config but i still get a 403.

@Configuration
public class MultipartUploadConfig {

    @Bean(name = "filterMultipartResolver")
    public MultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }
}

A quick solution if you are OK with sending the CSRF Token as a url parameter. In your html template.

<form .... th:action="@{/upload(${_csrf.parameterName}=${_csrf.token})}">
...
</form>

Spring Boot, Spring Boot Actuator is a sub-project of Spring Boot. It adds several production grade services to your application with little effort on your part. In this guide, you� Spring Boot is an open source Java-based framework used to create a micro Service. It is developed by Pivotal Team and is used to build stand-alone and production ready spring applications.

If you use Ajax, put token parameter in url, to action in form action:

url: "/uploadFile?${_csrf.parameterName}=${_csrf.token}"

It becomes like this:

function uploadFile() {
      $.ajax({
        url: "/uploadFile?${_csrf.parameterName}=${_csrf.token}",
        type: "POST",
        data: new FormData($("#upload-file-form")[0]),
        enctype: 'multipart/form-data',
        processData: false,
        contentType: false,
        cache: false,
        success: function () {
          // Handle upload success
          $("#upload-file-message").text("File succesfully uploaded");
        },
        error: function () {
          // Handle upload error
          $("#upload-file-message").text(
              "File not uploaded (perhaps it's too much big)");
        }
      });
    }

Getting Started, Spring Boot is an open-source micro framework maintained by a company called Pivotal. We describe what Spring Boot is and what it's used� As you read more Spring Getting Started guides, you will see more use cases for Spring Boot. This guide is meant to give you a quick taste of Spring Boot. If you want to create your own Spring Boot-based project, visit Spring Initializr, fill in your project details, pick your options, and download a bundled up project as a zip file.

You can do the following to provide the token on each Ajax call:

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);
});

There's another StackOverflow post that talks about this, that's where I found, but it's been a while since I saw it.

Spring Boot Reference Documentation, Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss. It takes an opinionated view of the� Spring Boot contains a comprehensive infrastructure support for developing a micro service and enables you to develop enterprise-ready applications that you can “just run”. Audience This tutorial is designed for Java developers to understand and develop production-ready spring applications with minimum configurations.

Getting Started, Final Answer: What is Spring Boot? Spring Boot is just a couple of AutoConfigurations classes (== normal Spring @Configurations), that create @� Spring Boot is an open-source micro framework maintained by a company called Pivotal. It provides Java developers with a platform to get started with an auto configurable production-grade Spring application.

What Is Spring Boot?, Spring Boot is basically an extension of the Spring framework which eliminated the boilerplate configurations required for setting up a Spring� Spring Boot is a Spring module that provides the RAD (Rapid Application Development) feature to the Spring framework. Our Spring Boot Tutorial includes all topics of Spring Boot such, as features, project, maven project, starter project wizard, Spring Initializr, CLI, applications, annotations, dependency management, properties, starters

spring-projects/spring-boot: Spring Boot, Spring Boot is a brand new framework from the team at Pivotal, designed to simplify the bootstrapping and development of a new Spring� Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss. It takes an opinionated view of the Spring platform so that new and existing users can quickly get to the bits they need.

Comments
  • see here: stackoverflow.com/questions/21514074/…
  • @smoggers i tried that but it doesn't work for me.
  • Did you ever get this working?
  • @inanutshellus no. i gave up and disabled CSRF for the time being...
  • @aepure it was for a toy project and i gave up on that. So i don't think that i can contribute anymore ...
  • @ChristosBaziotis: They are on answering spree -> same answer.
  • that's exposing the token in the URL, bad practice
  • that's exposing the token in the URL, bad practice
  • With Ajax, you can just add it to the request headers, like explained here stackoverflow.com/questions/21514074/…