Encoded slash (%2F) with Spring RequestMapping path param gives HTTP 400

谁说我不能喝 提交于 2019-11-26 22:47:39

问题


This is not a duplicate referenced question, because it is Spring specific. Whoever added that (3 years after the fact!) didn't bother to read the question or comment thread to see what the real answer was. The accepted answer isn't quite the answer, but the author of the answer never came back and edited it like I asked.

Given the restful method below, Spring 3.1 gives a 400 error with "The request sent by the client was syntactically incorrect ()." when the token parameter contains a URL encoded slash (%2F), for example "https://somewhere.com/ws/stuff/lookup/resourceId/287559/token/R4o6lI%2FbBx43/userName/jim" Without the %2F everything works fine. A 3rd party is already calling this service (of course!) so I can't change what they send, in the short term at least. Any ideas on how to work around this on the server side?

This problem is described very well here https://jira.springsource.org/browse/SPR-8662 though that issue is related to UriTemplate which I am not using that I can tell.

@RequestMapping("/ws/stuff/**")
@Controller
public class StuffController {
  @RequestMapping(value = "/ws/stuff/lookup/resourceId/{resourceId}/token/{token}/userName/{userName}", method = RequestMethod.GET)
   public @ResponseBody
   String provisionResource(@PathVariable("resourceId") String resourceId, @PathVariable("token") String token, @PathVariable("userName") String userName, ModelMap modelMap,
         HttpServletRequest request, HttpServletResponse response) {
      return handle(resourceId, userName, request, token, modelMap);
   }
}

Note: This is on Glassfish 3.1.2, and at first it was Grizzly/Glassfish not accepting the slash, but

-Dcom.sun.grizzly.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

fixed that.

asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-2.http.encoded-slash-enabled=true

didn't seem to help.


回答1:


This could be your answer: urlencoded Forward slash is breaking URL

I would suggest not putting that in the path, move it to a request param instead.

Work around:

You could change the RequestMapping to

@RequestMapping(value = "/ws/stuff/lookup/resourceId/**", method = RequestMethod.GET) 

and then parse the path variables manually from the request object.




回答2:


for spring-boot, the following did the trick

@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {

    public static void main(String[] args) throws Exception {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

}



回答3:


Here is a fix for Spring 3.2.4 (should work for other versions as well). One must overwrite the default UrlPathHelper

public class UrlPathHelperFixed extends UrlPathHelper {

    public UrlPathHelperFixed() {
        super.setUrlDecode(false);
    }

    @Override
    public void setUrlDecode(boolean urlDecode) {
        if (urlDecode) {
            throw new IllegalArgumentException("Handler [" + UrlPathHelperFixed.class.getName() + "] does not support URL decoding.");
        }
    }

    @Override
    public String getServletPath(HttpServletRequest request) {
        String servletPath = getOriginatingServletPath(request);
        return servletPath;
    }

    @Override
    public String getOriginatingServletPath(HttpServletRequest request) {
        String servletPath = request.getRequestURI().substring(request.getContextPath().length());
        return servletPath;
    }
}

And inject it to the Mapping Handler:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="order" value="-1"></property>
    <property name="urlPathHelper">
        <bean class="com.yoochoose.frontend.spring.UrlPathHelperFixed"/>
    </property>
</bean>

After a day of hard works it works now for me :-)

It was suggested to Spring team as https://jira.springsource.org/browse/SPR-11101




回答4:


For spring boot application this worked for me..

Version 1 Add

org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

to your application.properties file

Version 2 run your spring boot application like this.

static void main(String[] args) {
    System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
    SpringApplication.run this, args
}

Version 3 or run your java application with -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

This fixed %2F encoded slash path variable for me.




回答5:


I have found this solution which is working for me;

System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");

just before springApplication.run(args);

and add below code in Application class

 @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }



回答6:


We just ran into this issue at my office, we did what was suggestion above from what Solubris said where you put it in a query param. The only additional requirement is that the data could have an '&' as well, which would mess up the query param. All we had to do is encode the text before it is sent in the URL and even '&' were filtered out.




回答7:


Another answer would be to encode "/" twice, which would produce "%252F".
In your mapped endpoint, Spring will decode it back to "%2F". All you need more is to decode it one more time using something like this:

URLDecoder.decode(encoded_URL, "UTF-8");




回答8:


2019 Update for Spring Boot 2+ / Spring (Security) 5+ / Java 8+:

As my edit to iamiddy's answer was rejected I want to also provide the complete solution for Spring Boot 2 + as an separate answer.

The WebMvcConfigurerAdapter is deprecated with Spring5 / Java8 and can be replaced directly with the Interface WebMvcConfigurer ending up with:

@SpringBootApplication
public class Application extends WebMvcConfigurer {

    public static void main(String[] args) throws Exception {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

Plus you also need to configure Spring's (Strict)HttpFirewall to avoid the blocking of encoded slashes with the error message The request was rejected because the URL contained a potentially malicious String "%2F"

@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedSlash(true);    
    return firewall;
}

Spring Boot will use the above HttpFirewall Bean when available - otherwise it might be necessary to configure the WebSecurity as mentioned here:



来源:https://stackoverflow.com/questions/13482020/encoded-slash-2f-with-spring-requestmapping-path-param-gives-http-400

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