Sorin Postelnicu
Sorin Postelnicu

Reputation: 1301

@PathVariable containing backslash quote returns 400 Bad Request

If you run this simple RestController with Spring Boot (2.5.3):

@RestController
public class SampleRestController {

    @GetMapping("/search/{criteria}")
    public String hello(@PathVariable(name = "criteria") String criteria) {
        return "Hello: " + criteria;
    }

}

And try to open this link in your browser:

 http://localhost:8080/search/%22%5C%22bug%5C%22%22 

Then you will get "400 Bad Request", returned by the embedded Tomcat.

I don't understand, is this a bug in Tomcat ? Is this not a valid URL ?

EDIT: As per some of the replies: I went step-by-step through the Tomcat 9.0.50 source-code and saw the line about ALLOW_BACKSLASH. And neither of the values true or false is good for me, because with true it replaced \ with / and with false it returns 400 Bad Request. What I needed was to allow backslash without replacing it with slash.

My question is really whether this is a bug in Tomcat, since for me the URL seems to be valid. I am not technically putting a \ into the URL, I am putting a %-encoded backslash. What is the purpose of the %-encoding if not to allow the user to send any character in the URL ?

Upvotes: 3

Views: 3287

Answers (5)

Zavael
Zavael

Reputation: 2468

On Spring Boot 3.2.1 and Tomcat 10.1.17 I had to go as far as defining both these beans:

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

@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer()
{
    return factory -> factory.addConnectorCustomizers(connector -> {
        connector.setAllowBackslash(true);
        connector.setEncodedSolidusHandling(
            EncodedSolidusHandling.DECODE.getValue());
    });
}

I tested it with backslash and encoded backslash (%5C). Putting EncodedSolidusHandling.DECODE or EncodedSolidusHandling.PASS_THROUGH didn't made any difference, the behaviour was the same. But at least the request finally entered the Spring filter.

Upvotes: 0

Amit Jain
Amit Jain

Reputation: 127

Seems like tomcat block those request before reaching it to dispatcher servlet.

Using Spring boot 3.2.4 version 10.x.x. Let suppose in path variable it contains %2F or %5C getting 400 Bad request. I have tried the above methods somehow it didn't work for me. Thanks to this post But this worked for me you can try that

@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer()
{
    return factory -> factory.addConnectorCustomizers(connector -> {
        connector.setAllowBackslash(true);
        connector.setEncodedSolidusHandling(
                EncodedSolidusHandling.DECODE.getValue());
    });
}

Upvotes: 0

Piotr P. Karwasz
Piotr P. Karwasz

Reputation: 16045

While samabcde's answer provides a solution for your problem, let me answer to your more general questions:

  • your URL is perfectly valid although RFC 3986, section 7.3 allows some restriction to be imposed for security reasons,
  • these restrictions are not a Tomcat bug, as they were introduced as an answer to CVE-2007-0450. Before Tomcat 6.0.10 the sequences /, %2F and %5C were used to split the request URI into components. If Tomcat was behind a proxy that forwarded only an application (let's say /app), you could use /app/%5C../manager/html to access Tomcat Manager.

If you set org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true you expose your system to the aforementioned vulnerability and all %5C sequences will appear as / in the servletPath and pathInfo ServletRequest properties. Since the requestURI property contains the undecoded URI path (cf. this question) your example will work.

Upvotes: 1

samabcde
samabcde

Reputation: 8114

Refer to Piotr P. Karwasz comments above for better explanation.

The tomcat version correspond to Spring Boot (2.5.3) is 9.0.50. By checking the source code of CoyoteAdaptor and Tomcat System parameter documentation, the url checking is configured by a flag ALLOW_BACKSLASH through System Property org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH, with false as default value.

...
    protected static final boolean ALLOW_BACKSLASH =
        Boolean.parseBoolean(System.getProperty("org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH", "false"));

...

To allow backslash in the URL, we can add below when running the application.

-Dorg.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true

This property is replaced after tomcat 10.0.0-M4.

Remove org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH system property, replaced by the allowBackslash attribute on the Connector. (remm)

Upvotes: 2

Vitali
Vitali

Reputation: 176

Yes it seems like an invalid URL, you also get an error by Spring Boot refering to RFC 7230 and RFC 3986 specifications. But you could use some query parameter to avoid this error, e.g.:

@GetMapping("/search")
public String hello(@RequestParam(name = "criteria", required = false) String criteria) {
    return "Hello: " + criteria;
}

And call it like:

http://localhost:8080/search?criteria=%22%5C%22bug%5C%22%22 

Upvotes: 1

Related Questions