2

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 ?

Sorin Postelnicu
  • 1,271
  • 1
  • 10
  • 15
  • This could help https://stackoverflow.com/a/33822129/2834978 – LMC Aug 04 '21 at 14:55
  • 1
    Does this answer your question? [Springboot doesn't let through percentage and backslash in URL](https://stackoverflow.com/questions/51108291/springboot-doesnt-let-through-percentage-and-backslash-in-url) – Piotr P. Karwasz Aug 04 '21 at 20:16
  • Thanks @PiotrP.Karwasz that question does indeed help. I don't know why I did not find it yesterday. The conclusions from that one: One answer mentions that backslash is allowed in Jetty, so this seems to be a Tomcat issue. Another answer mentions how to allow backslash in Spring. And a third answer mentions that, according to the HTTP RFCs, we are not allowed to use backslash in URL, even if it's %-encoded. – Sorin Postelnicu Aug 05 '21 at 09:15
  • 1
    It's not a bug, it's a _security feature_! IMHO the `encodedSolidusHandling` attribute in your [connector's configuration](https://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Common_Attributes) should also apply to the backslash (reverse solidus), but you should better ask on [tomcat-users](https://tomcat.apache.org/lists.html). [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-7.3) allows for a special treatment of backslash, but does not mandate it. – Piotr P. Karwasz Aug 05 '21 at 09:49
  • 1
    The ban on backslashes was introduced due to [this vulnerability](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0450). – Piotr P. Karwasz Aug 05 '21 at 10:35
  • 1
    Thank you, @PiotrP.Karwasz . If you can sum this up into an answer, I will approve your answer. (The other two answers are useful, but both are incomplete regarding to what I needed to know.) The answer most appropriate for my question is this answer for the other question you forwarded to me: https://stackoverflow.com/a/51109103/271104 but it would make even more sense with your clarifications added to it. – Sorin Postelnicu Aug 06 '21 at 13:38

3 Answers3

2

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)

samabcde
  • 6,988
  • 2
  • 25
  • 41
  • `ALLOW_BACKSLASH=true` has the side effect of converting `\ ` into `/`, so there is no way to pass a backslash in an URI path to Tomcat – Piotr P. Karwasz Aug 04 '21 at 20:10
  • samabcde and @piotr-p-karwasz Thanks for the answers. Please see my edit of the question. – Sorin Postelnicu Aug 05 '21 at 09:07
  • @samabcde, actually your answer provides a solution: the replacement of `\ ` into `/` is done only for Tomcat's internal routing purposes. The replacement takes place in the `servletPath` and `pathInfo` request properties (which are URL decoded, cf. [this answer](https://stackoverflow.com/a/1064589/11748454)). Spring actually uses `requestURI`, so the backslash will stay. – Piotr P. Karwasz Aug 06 '21 at 15:32
  • 1
    @PiotrP.Karwasz, Thx for your comment. It seems my eye just get confused with "\" and "/". I thought you are right when reading your previous comment and I see "/" when I load my testing page. And now I see "\" again. – samabcde Aug 06 '21 at 15:53
1

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 
Vitali
  • 176
  • 1
  • 3
  • Thanks for the answer, @Vitali. My question still stands: WHY is the URL invalid? I am not technically sending a backslash in the URL. I am sending only valid URL characters. What is the purpose of the %-encoding if not to allow the user to send any character in the URL ? – Sorin Postelnicu Aug 05 '21 at 09:11
1

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.

Piotr P. Karwasz
  • 12,857
  • 3
  • 20
  • 43