Error loading 403 file - Spring MVC

In my Spring MVC project, I am trying to upload a file through a simple form.

HTML form:

<form method="POST" enctype="multipart/form-data" action="/upload"> <label>Select File</label> <input type="file" name="file"/> </form> 

My controller:

 @Controller public class FileController { @RequestMapping(value="/upload", method=RequestMethod.POST) public @ResponseBody String handleFileUpload( @RequestParam("name") String name, @RequestParam("file") MultipartFile file){ if (!file.isEmpty()) { try { //do stuff } catch (Exception e) { return "You failed to upload " + name + " => " + e.getMessage(); } } else { return "You failed to upload " + name + " because the file was empty."; } } } 

Security Configuration:

 @Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/upload").permitAll() .and() .exceptionHandling().accessDeniedPage("/403") } } 

However, I get a 403: Forbidden error and each time it redirects to my 403.html view

So far I have been trying to specify MultipartFilter before Spring Security Filter is initialized in a separate class, but fails

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

Any ideas?

UPDATE: enabling my WebAppInitializer

 @Configuration @Import({ WebSecurityConfig.class }) public class WebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { System.out.println(":::Starting My App:::"); AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(WebMVCConfig.class); context.setServletContext(servletContext); context.setConfigLocation("com.myApp.configuration"); } } 

I have a list of servlet request attributes that returns error 403:

 javax.servlet.forward.request_uri javax.servlet.forward.context_path javax.servlet.forward.servlet_path __spring_security_scpf_applied org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE SPRING_SECURITY_403_EXCEPTION org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER springMacroRequestContext themes thymeleafEvaluationContext org.springframework.security.web.FilterChainProxy.APPLIED _csrf org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.FILTERED org.springframework.security.web.csrf.CsrfFilter@539743f9.FILTER ED beans springRequestContext org.springframework.web.servlet.HandlerMapping.introspectTypeLevelMapping org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER org.springframework.web.servlet.DispatcherServlet.CONTEXT org.springframework.core.convert.ConversionService execInfo org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER org.springframework.web.servlet.resource.ResourceUrlProvider org.springframework.web.servlet.DispatcherServlet.OUTPUT_FLASH_MAP org.springframework.web.servlet.HandlerMapping.bestMatchingPattern org.springframework.security.web.csrf.CsrfToken org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER 

Update # 2: This is definitely a CSRF issue; when I include the following in my WebSecurityConfig , I don't get 403

 .csrf().disable() 
+6
source share
3 answers

This is described in the CSRF - File Upload section of the Spring Security Help. You have two options:

MultipartFilter Hosting Before Spring Security

The first parameter is to make sure that MultipartFilter is specified before the Spring Security filter. Specifying the MultipartFilter filter before the Spring security filter means that there is no authorization to call MultipartFilter, which means that anyone can host temporary files on your server. However, only authorized users will be able to send a file that is processed by your application. In general, this is the recommended approach, since temporary file loading should have a negative effect on most servers.

To ensure that MultipartFilter is specified before Spring's 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 that a MultipartFilter is specified before the Spring security filter with the XML configuration, users can verify that the MultipartFilter is placed before springSecurityFilterChain in 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> 

Enable CSRF token in action

If it is unacceptable to allow unauthorized users to upload temporary files, an alternative is to place a MultipartFilter after the Spring security filter and include CSRF as a request parameter in the form action attribute. An example with jsp is shown below.

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

The disadvantage of this approach is that query parameters may be skipped. It is more ingeniously considered that it is best practice to place sensitive data inside the body or headers to ensure that it does not leak. For more information, see RFC 2616 Section 15.1.3. Encoding sensitive information in a URI .

+6
source

The quick fix for me was as follows

 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Upload File Request Page</title> </head> <body> <form method="POST" action="file/uploadFile?${_csrf.parameterName}=${_csrf.token}" enctype="multipart/form-data"> File to upload: <input type="file" name="file"><br /> Name: <input type="text" name="name"><br /> <br /> <input type="submit" value="Upload"> Press here to upload the file! </form> </body> </html> 

The controller code is as follows:

 package com.student.controller; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.security.Principal; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; @Controller @RequestMapping("/file") public class FileUploadController { @RequestMapping(value = "", method = RequestMethod.GET) public String index(ModelMap modelMap,Principal principal,HttpServletRequest request) { return "uploadfile"; } @RequestMapping(value = "/uploadFile", method = RequestMethod.POST) public @ResponseBody String uploadFileHandler(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { try { byte[] bytes = file.getBytes(); // Creating the directory to store file String rootPath = System.getProperty("catalina.home"); File dir = new File(rootPath + File.separator + "tmpFiles"); if (!dir.exists()) dir.mkdirs(); // Create the file on server File serverFile = new File(dir.getAbsolutePath() + File.separator + name); BufferedOutputStream stream = new BufferedOutputStream( new FileOutputStream(serverFile)); stream.write(bytes); stream.close(); return "You successfully uploaded file=" + rootPath+name; } catch (Exception e) { return "You failed to upload " + name + " => " + e.getMessage(); } } else { return "You failed to upload " + name + " because the file was empty."; } } } 

I added the following code to the spring dispatch file

 <!-- upload files --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- setting maximum upload size --> <property name="maxUploadSize" value="100000" /> </bean> 
0
source

The solution for me is to disable csrf() in my WebSecurityConfig for example:

  @EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable(); } } 

And now I can just upload the multi-component file :)

0
source

All Articles