spring-cloud / spring-cloud/spring-cloud-gateway
Possible XForwardedHeadersFilter issue around X-Forwarded-Proto?
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 4.9k
- Forks
- 3.5k
- Avg merge
- 20h 57m
- Merged PRs (30d)
- 8
Description
Summary
It would seem to me that the logic around determining the X-Forwarded-Proto header in XForwardedHeadersFilter needs to be adapted for the possibility that spring-cloud-gateway itself is behind a reverse proxy.
Context
I have the common issue that people have with springdoc (yes, a different project) when behind a reverse proxy, namely that for springdoc to work correctly, the X-Forwarded-* headers need to be correctly set.
The answer here was particularly helpful.
That said, the setup we have is:
- https request comes in to nginx reverse proxy
- nginx does ssl termination and then forwards to something like
http://spring-cloud-gateway:7100(note the http, not https) - spring-cloud-gateway then forwards on to
http://someservice:someport
I.e. my service with springdoc in it is not immediately behind a reverse proxy, it is also behind spring cloud gateway.
If I remove spring cloud gateway and proxy direct from nginx to my service, I can easily ensure the headers are correct, and everything works fine.
However with spring cloud gateway in the mix this is a little trickier. I believe the XForwardedHeadersFilter is not setup to work in this kind of service layout.
(Caveat: it may be that a service layout like this is nonsensical, but alas it is what my organisation has, so I have to work with it for now)
The Alleged Issue
So the particular issue I seem to be encountering is:
In nginx I set (among others) proxy_set_header X-Forwarded-Proto $scheme;
When spring-cloud-gateway then receives the proxied request, it does:
String proto = request.getURI().getScheme();
But if you look at how scheme is determined in java.net.URI it sems to me it is parsing the full request url for http or https (which I guess it has to).
So the code:
String proto = request.getURI().getScheme();
if (isProtoEnabled()) {
write(updated, X_FORWARDED_PROTO_HEADER, proto, isProtoAppend());
}
will take the proto of the proxied request (http://spring-cloud-gateway:7100), regardless of whether a X-Forwarded-Proto header exists or not.
I can fix this for my scenario easily enough by adding my own custom HttpHeadersFilter, but should the code in XForwardedHeadersFilter perhaps not be updated to look for an X-Forwarded-Proto header, and if it exists, rather use that?
Or, since the client could spoof that, could that somehow introduce a security risk or something?
Or... is it simply not expected that spring-cloud-gateway should run behind a reverse proxy, and therefore a change like this is an unreasonable request? (I don't actually see any utility in such a setup, but alas I must live with it for now)
NOTE: this may also apply to some of the other X-Forwarded-* headers, I'm not sure. Still experimenting a bit.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read XForwardedHeadersFilter.java around line 199, focusing on request.getURI().getScheme(), the existing X-Forwarded-Proto header, and HttpHeadersFilter behavior. Determine the intended handling when the gateway is behind nginx, including whether honoring the incoming header creates a spoofing risk; done means the behavior and any required coverage are clearly defined.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring, spring-boot
- Domain
- api, backend, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100