spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.03k stars 40.66k forks source link

Encoded slash in path variable causes error 400 in WebFlux - regression in Spring Boot 3.3.5 #42907

Closed kdebski85 closed 1 hour ago

kdebski85 commented 1 hour ago

I develop a Spring WebFlux application with Netty. After upgrade of Spring Boot from 3.3.4 to 3.3.5, http status 400 is returned when a path contains encoded slash. The encoded slash is a part of path variable.

For example, the following endpoint returns status 400 for GET /api/a%2Fb/foo in 3.3.5.

    @GetMapping(path = "/api/{param}/foo", produces = APPLICATION_JSON_VALUE)
    public Mono<String> foo(@PathVariable String param) {
        return Mono.just(param);
    }

In 3.3.4, exactly same request returned 200 with a/b in the response.

bclozel commented 1 hour ago

I assume there is something else going on. I cannot reproduce this behavior.

import reactor.core.publisher.Mono;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @GetMapping(path = "/api/{param}/foo", produces = MediaType.TEXT_PLAIN_VALUE)
    public Mono<String> foo(@PathVariable String param) {

        return Mono.just(param);
    }
}
curl -v http://localhost:8080/api/a%2Fb/foo
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /api/a%2Fb/foo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 3
<
* Connection #0 to host localhost left intact
a/b%      

Maybe your application has Spring Security configured? In this case, this is probably due to the recent introduction of ServerWebExchangeFirewall, see https://github.com/spring-projects/spring-security/issues/15991. In this case, the reference documentation might help you with this or you can reach out to the Spring Security team.

kdebski85 commented 1 hour ago

I debugged that the issue is caused by org.springframework.security.web.server.firewall.StrictServerWebExchangeFirewall and downgrading to org.springframework.security:spring-security-web:6.3.3 resolves it.

I found that there is a method https://docs.spring.io/spring-security/reference/6.4-SNAPSHOT/api/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.html#setAllowUrlEncodedSlash(boolean)

Why such breaking change was introduced in a hotfix version? How to configure StrictServerWebExchangeFirewall in Spring Boot?

bclozel commented 1 hour ago

Why such breaking change was introduced in a hotfix version? How to configure StrictServerWebExchangeFirewall in Spring Boot?

I guess those are questions for the Spring Security team. Maybe ask this question on StackOverflow? Have you tried contributing your own StrictServerWebExchangeFirewall bean to the application context?

kdebski85 commented 5 minutes ago

I tried my custom StrictServerWebExchangeFirewall, but it was unused.

The issue was that setting the firewall was added after the release: https://github.com/spring-projects/spring-security/commit/3ba1263d64a1bd371c6d324e116c565aa7b0d7e9

For a time being, I will use BeanPostProcessor approach mentioned at: https://github.com/spring-projects/spring-security/issues/15974