Reputation: 990
I am trying to upload a file with a web application using Spring MVC 4 but I am getting an error:
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
Spring version:
Spring Version 4.1.7.RELEASE
Spring Security 4.0.1.RELEASE
Code:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>FATCA Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-web-servlet.xml
</param-value>
</context-param>
<servlet>
<servlet-name>spring-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-web</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
spring-web-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:property-placeholder location="classpath:webapp.properties" />
<context:annotation-config />
<context:component-scan base-package="com.opessoftware" />
<mvc:annotation-driven />
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
Settings.jsp
<form:form method="POST" action="uploadFile.html"
enctype="multipart/form-data" security="none">
<table style="width: 100%" border="1">
<tr>
<td colspan="1" style="text-align: left"><input
type="file" name="file" style="width: 100%;" /></td>
<td colspan="1" style="text-align: left"><input
type="submit" value=<spring:message code="uploadSettings" /> />
</td>
</tr>
</table>
</form:form>
Post request payload contents after submitting a file called test.txt
that contains the string "Test":
Content-Type: multipart/form-data; boundary=---------------------------83935555814334632461054528816
Content-Length: 368
-----------------------------83935555814334632461054528816
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
Test
-----------------------------83935555814334632461054528816
Content-Disposition: form-data; name="_csrf"
41f3dc0a-b97f-4dac-bc49-21e02be53818
-----------------------------83935555814334632461054528816--
Upvotes: 4
Views: 4137
Reputation: 28376
I fixed this by following the general advice in the second point of the accepted answer to Spring Security 3.2, CSRF and multipart requests, but using Spring Security 4.0.1.RELEASE instead of version 3.2.
Updated the Web application from Servlet API 2.4 to Servlet API 3.0:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
....
</web-app>
Using Java based configuration, created a StandardServletMultipartResolver
which uses the multipart handling of Servlet 3.0 and does not require commons-fileupload
. Note that the original implementation neglected to explicitly create any multipart resolver, though it did include dependency commons-fileupload
in the Maven project.
@Configuration
public class WebApplicationConfiguration {
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
}
Added "multipart-config" to the DispatcherServlet
:
In web.xml
:
<servlet>
<servlet-name>spring-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<multipart-config>
<location>/tmp</location>
<max-file-size>1000000</max-file-size>
<max-request-size>1000000</max-request-size>
<file-size-threshold>10000</file-size-threshold>
</multipart-config>
</servlet>
Using Java:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfiguration.class);
}
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
final XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/spring-web-servlet.xml");
final ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcher",
new DispatcherServlet(appContext));
registration.setLoadOnStartup(1);
registration.addMapping("/");
registration.setMultipartConfig(new MultipartConfigElement("", 1000000, 1000000, 100000));
}
}
Removed dependency commons-fileupload
from the Maven project.
Upvotes: 4