You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TL;DR: When a Spring Gateway application detects that a cloud platform is present the forwarding behavior changes in potentially a dangerous way.
The bug
We recently upgraded our Spring Cloud Gateway based API gateway from Spring Boot 3.2 / Spring Cloud 2023 to Spring Boot 3.4 / Spring Cloud 2024. For some requests the gateway resides behind another proxy that does some mild path rewriting and being a nice proxy sets these headers:
After the upgrade I noticed those requests failing, as they were being rewritten in a strange manner, e.g. https://example.com/something-external/my-service/get/things should be rewritten to https://my-service/get/things but instead where changed to https://my-service/something-external/get/things and would 404.
https://example.com/something-external/my-service/get/things
https://my-service/get/things <- old behavior
https://my-service/something-external/get/things <- 404
Some testing showed that I could also set the x-forwarded-host header to coerce the gateway to contact outside servers. Spooky.
More digging revealed that this error was caused by the NettyWebServerFactoryCustomizer deciding to enable special forward header treatment when the presence of a cloud-plattform is detected (with isUsingForwardHeaders(), which all currently are). The DefaultHttpForwardedHeaderHandler would then rewrite the request URI to to a new host and path.
In total I found three code paths through which this would be enabled: Either straight through the ForwardedHeaderTransformer and server.forward-headers-strategy=framework, or via the NettyWebServerFactoryCustomizer setting setUseForwardHeaders to true when getOrDeduceUseForwardHeaders detected a cloud platform or the server.forward-headers-strategy=native. Only explicitly setting server.forward-headers-strategy=none protected us from this.
Noteworthy, the default config is also dangerous if you use any cloud platform integration and it detects a cloud platform.
Why is this bad?
For one, I could not find any mention of a behavior change in the documentation, so at minimum this is a documentation issue. Then, at least to me personally, this is an entirely unexpected behavior. Both the forwarding and that it engages only in some circumstances. The most worrying part is the rewrite of the host through the x-forwarded-host header, which opens up some potential attacks.
What should change?
Documentation
The default should never allow rewriting URIs by X-Forwarded headers
???
Workarounds
Obviously setting the server.forward-headers-strategy=none prevents this issue. Disabling spring.cloud.gateway.x-forwarded.* may work (not tested). Not setting the X-Forwarded headers also prevents this (duh). And not letting the X-Forwarded headers into your backend is probably a good practice anyway.
Versions affected
Spring Boot 3.4.1 / Cloud 2024.0.0: Present
Spring Boot 3.3.7 / Cloud 2023.0.5: No, dangerous only when explicitly setting server.forward-headers-strategy=framework.
Spring Boot 3.2.0 / Cloud 2023.0.5: No, dangerous only when explicitly setting server.forward-headers-strategy=framework.
Sample
I wrote tests covering all configurations that seemed susceptible to this. The bad ones will fail for "evil" requests.
While server.forward-headers-strategy=none worked for us in most cases, it still breaks things when we have a gateway running as a proxy between frontend and backend with Spring Security and CORS, so it's not ideal.
Same issue mentioned here - #3662
TL;DR: When a Spring Gateway application detects that a cloud platform is present the forwarding behavior changes in potentially a dangerous way.
The bug
We recently upgraded our Spring Cloud Gateway based API gateway from Spring Boot 3.2 / Spring Cloud 2023 to Spring Boot 3.4 / Spring Cloud 2024. For some requests the gateway resides behind another proxy that does some mild path rewriting and being a nice proxy sets these headers:
After the upgrade I noticed those requests failing, as they were being rewritten in a strange manner, e.g.
https://example.com/something-external/my-service/get/things
should be rewritten tohttps://my-service/get/things
but instead where changed tohttps://my-service/something-external/get/things
and would 404.Some testing showed that I could also set the
x-forwarded-host
header to coerce the gateway to contact outside servers. Spooky.More digging revealed that this error was caused by the
NettyWebServerFactoryCustomizer
deciding to enable special forward header treatment when the presence of a cloud-plattform is detected (withisUsingForwardHeaders()
, which all currently are). TheDefaultHttpForwardedHeaderHandler
would then rewrite the request URI to to a new host and path.In total I found three code paths through which this would be enabled: Either straight through the
ForwardedHeaderTransformer
andserver.forward-headers-strategy=framework
, or via theNettyWebServerFactoryCustomizer
settingsetUseForwardHeaders
to true whengetOrDeduceUseForwardHeaders
detected a cloud platform or theserver.forward-headers-strategy=native
. Only explicitly settingserver.forward-headers-strategy=none
protected us from this.Noteworthy, the default config is also dangerous if you use any cloud platform integration and it detects a cloud platform.
Why is this bad?
For one, I could not find any mention of a behavior change in the documentation, so at minimum this is a documentation issue. Then, at least to me personally, this is an entirely unexpected behavior. Both the forwarding and that it engages only in some circumstances. The most worrying part is the rewrite of the host through the
x-forwarded-host
header, which opens up some potential attacks.What should change?
X-Forwarded
headersWorkarounds
Obviously setting the
server.forward-headers-strategy=none
prevents this issue. Disablingspring.cloud.gateway.x-forwarded.*
may work (not tested). Not setting the X-Forwarded headers also prevents this (duh). And not letting theX-Forwarded
headers into your backend is probably a good practice anyway.Versions affected
server.forward-headers-strategy=framework
.server.forward-headers-strategy=framework
.Sample
I wrote tests covering all configurations that seemed susceptible to this. The bad ones will fail for "evil" requests.
The text was updated successfully, but these errors were encountered: