jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.83k stars 1.91k forks source link

URIUtil works in combination with UriCompliance #11453

Closed VnzBzk closed 6 months ago

VnzBzk commented 6 months ago

Jetty version(s) 12.0.6

Jetty Environment ee8

Java version/vendor openjdk version "17.0.8.1" 2023-08-24 LTS OpenJDK Runtime Environment (build 17.0.8.1+1-LTS) OpenJDK 64-Bit Server VM (build 17.0.8.1+1-LTS, mixed mode, sharing)

OS type/version Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy

Question Jetty returns HTTP ERROR 400 Invalid request although we configured Jetty with following HttpConfiguration:

private static void manageHttpConfig(Server server, int port) {
    HttpConfiguration httpConfig = new HttpConfiguration();
    httpConfig.setSendServerVersion(false);
    httpConfig.setUriCompliance(UriCompliance.from(Set.of(
            UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR)));

When requesting for a specific context like this http://localhost:8080/energy/values/test%2Ftest the %2F wont lead to the BadMessageException in the HttpConnection (this works) but it will be converted back to a / in the URIUtil.decodePath. This leads to a wrong pathInContext within the Request of the Context. Is this a bug or have i missed a specific Configuration?

The Jetty log looks like this:

DEBUG org.eclipse.jetty.ee8.nested.HttpChannel      - action DISPATCH HttpChannel@4e34ce4a{s=HttpChannelState@3f163f2c{s=HANDLING rs=BLOCKING os=OPEN is=IDLE awp=false se=false i=true al=0},r=3,c=false/false,a=HANDLING,uri=http://localhost:8080/energy/values/test%2Ftest,age=0}

DEBUG org.eclipse.jetty.ee8.nested.ContextHandler   - REQUEST GET /energy/values/test/test ?null on HttpChannel@4e34ce4a{s=HttpChannelState@3f163f2c{s=HANDLING rs=BLOCKING os=OPEN is=IDLE awp=false se=false i=true al=0},r=3,c=false/false,a=HANDLING,uri=http://localhost:8080/energy/values/test%2Ftest,age=0}
joakime commented 6 months ago

The configuration ...

    httpConfig.setUriCompliance(UriCompliance.from(Set.of(
            UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR)));

Means you are allowing AMBIGUOUS_PATH_SEPARATOR which will allow the %2F through the HttParser and handling is allowed to begin.

There's a testcase present in PR #11454 that shows this is working, at least for jetty-core.

gregw commented 6 months ago

@VnzBzk The spec for ee8 had not considered how characters like %2F can be confusing. The methods like getServletPath and getPathInfo are documented to return a decoded string, so the %2F is decoded to "/". This can be confusing / ambiguous, so by default, Jetty does not allow such requests into the servlet container as they may bypass security constraints or trip up the application in some other way. By configuring UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR you allow the request into the container, but we still cannot do anything about the ambiguous decoding.

If you wish to handle such URIs then you are best to use the getRequestURI() method to obtain the encoded path and then you can do your own handling that is able to deal with the %2F correctly.

joakime commented 6 months ago

@VnzBzk also note that using %2F in the path section of a URI is no longer possible in Servlet 6, you should migrate the usage of %2F to the query section.

See Servlet 6 changes around URI path (encoding / decoding / normalization / equivalence / etc):

This updated URI path behavior is even in the Servlet 6 TCK. Many Servlet implementations provide non-standard configuration to bypass these rules, but the behavior is different in each implementation. Most libraries that depend on the Servlet spec (spring / jersey / etc) do not recommend using these non-standard configurations.

joakime commented 6 months ago

For others that find this issue in the future, here's the Servlet 6 Spec documentation.

https://github.com/jakartaee/servlet/blob/6.0.0-RELEASE/spec/src/main/asciidoc/servlet-spec-body.adoc#352-uri-path-canonicalization

See 3.5.2. URI Path Canonicalization and point 10 in that section in particular for all of the various types of URI paths that can trigger the Servlet 6 rules mentioned in this issue.

janbartel commented 6 months ago

Looks like the question has been addressed, so I'll close this issue.

janitza-bjag commented 6 months ago

We have some servlets with spec 4 running with Jetty 10.0.12 where "%2F" in path mapping works as expected ... means that rest/vari%2Fable/ in the path mapping results in "vari/able" for variable type

@Path ("rest/{type}") public Response getValue(@PathParam ("type") String type)

With Jetty 10.0.15 this doesn't work anymore

joakime commented 6 months ago

@janitza-bjag Jetty versions 11 and older are now at End of Community Support.

See:

Also note that your versions 10.0.12 and 10.0.15 are subject to several security advisories.

Finally, the %2F was always ambiguous and not able to be properly supported by the Servlet spec (due to decisions long long ago, back in the HTTP/0.9 era, with regards to encoding / decoding of paths and the other APIs that require a stable and reproducible path).

It wasn't until Servlet 6.0 where the ambiguous nature of that encoded path separator was codified as not supported, and implementations must return 400 Bad Request when it receives a request path with an encoded %2F.

Note: there are MANY things that can appear in the path portion of a URL/URI that can cause problems in the Servlet spec, the encoded %2F is just one of them, see the updated Servlet spec about "Rejecting Suspicious Sequences" to get a feel for the kinds of request URL/URIs that have always caused problems with the Servlet spec.