spring-cloud / spring-cloud/spring-cloud-gateway

Possible XForwardedHeadersFilter issue around X-Forwarded-Proto?

Open
#2,762 3 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

waiting-for-triage
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.