Reputation: 1301
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
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
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
Reputation: 16045
While samabcde's answer provides a solution for your problem, let me answer to your more general questions:
/
, %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
Reputation: 8114
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
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