Webflux multipart/form-data, csrf enabled, with and without file upload getting Invalid CSRF Token

放肆的年华 提交于 2019-12-06 03:34:37

Take a look at Spring Security's official recommendation: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-multipart

There are basically two ways of doing it: (1) placing MultipartFilter before Spring Security filter and (2) include the CSRF token in the form action, as you are doing. The first option is the recommended one:

The first option is to ensure that the MultipartFilter is specified before the Spring Security filter. Specifying the MultipartFilter before the Spring Security filter means that there is no authorization for invoking the MultipartFilter which means anyone can place temporary files on your server. However, only authorized users will be able to submit a File that is processed by your application. In general, this is the recommended approach because the temporary file upload should have a negligble impact on most servers.

To ensure MultipartFilter is specified before the Spring Security filter with java configuration, users can override beforeSpringSecurityFilterChain as shown below:

public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }
}

To ensure MultipartFilter is specified before the Spring Security filter with XML configuration, users can ensure the element of the MultipartFilter is placed before the springSecurityFilterChain within the web.xml as shown below:

<filter>
    <filter-name>MultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>MultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note that, if you still want to use form action, query parameters can be leaked. Try to change your "headerName" to "parameterName":

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">

EDIT: In case you can't switch to a servlet-based container (such as Jetty or Tomcat) and the form action recommendation doesn't work, there's a recent Stack Overflow thread discussing this issue.

One of the developers reported to workaround the issue using AJAX:

I solved this problem by:

  • sending the multi-part file using vanilla javascript, like in Mozilla's guide
  • adding the _csrf token in the HTML header, in meta tags, like in the Spring guideline for sending the CSRF token with Ajax
  • instead of using jquery, adding it directly to the XHR object

var csrfToken = $("meta[name='_csrf']").attr("content"); var csrfHeader = $("meta[name='_csrf_header']").attr("content"); XHR.setRequestHeader(csrfHeader, csrfToken); XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary); XHR.send(data);

The same developer reported this issue to Spring, but didn't get any attention yet.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!